> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.jelliu.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.jelliu.co/_mcp/server.

# Replay stored events

POST https://api.jelliu.co/api/webhooks/{webhookId}/replay
Content-Type: application/json

Queues a new delivery to this endpoint for every stored event created between `from` and `to`
(inclusive) that matches the endpoint's current `events` and `filters`. Use it after a receiver
outage, or to backfill a newly created endpoint. Each replayed event keeps its original `id`, so
the `webhook-id` header matches the original delivery and existing deduplication applies.

Events are retained for 30 days, and only events from the last 30 days can be replayed. A range
containing more than 1000 events is rejected; narrow it or filter by `types`. Test events
(`webhook.test`, and the examples sent with `POST /api/webhooks/{webhookId}/test`) are never
replayed. Events are stored only while the workspace has at least one webhook (active or
disabled), so events from before the first webhook cannot be replayed.

Replayed deliveries are processed by the standard dispatcher (same retries, same headers), are
marked `manual: true` in the log, and do not affect endpoint health. A disabled endpoint cancels
them; enable it first.

**Side effects.** Inserts one delivery per matching event; they are sent within seconds.

**Idempotency.** Not idempotent: calling it twice queues every event twice (with the same
`webhook-id`, so a deduplicating receiver is unaffected).

**Access**

* **Required scope:** `full`. Human users need the owner or admin role.
* **Rate limit:** General API (120–600 requests/min per workspace, by plan) plus the configuration-mutations limit — 10 requests/min per workspace, shared with other configuration changes. See [Rate limits](/rate-limits).
* **Plan:** Requires an active subscription (`active`, `trialing` or `past_due`); without one the request is refused with `403 BILLING_ERROR` (`metadata.kind: subscription_required`). See [Billing and usage](/platform/billing-and-usage#without-an-active-subscription).

Reference: https://developer.jelliu.co/api-reference/webhooks/post-webhooks-by-webhook-id-replay

## Authentication

- `Authorization` header (bearer token, required) — Workspace API key: `jl_` followed by 64 lowercase hex characters, created by the workspace owner in the dashboard (**Settings → API Keys**) and sent as `Authorization: Bearer jl_...`. The plaintext is shown once, at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys. | Scope | GET / HEAD | POST / PUT / PATCH / DELETE | Admin-only routes | | --- | --- | --- | --- | | `read` | Yes | No | No | | `write` | Yes | Yes | No | | `full` | Yes | Yes | Yes | Operations restricted to admins or owners reject keys without the `full` scope with `403`, and say so in their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret — that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds. See [Authentication](/authentication).

## Request

### Path parameters

- `webhookId` (string, required) — UUID of the outbound webhook endpoint, returned as `id` by `GET /api/webhooks`. It must belong to the authenticated workspace; an id from another workspace, an unknown id or a value that is not a UUID answers `404`.

### Body (application/json)

This endpoint expects an object.

- `from` (datetime, required) — Start of the range, ISO 8601 with a time zone offset or `Z`. No earlier than 30 days ago.
- `to` (datetime, required) — End of the range, ISO 8601. Must not be before `from`.
- `types` (list of string, optional) — Only replay these event types. Each must be a subscribable type (`"*"` is not accepted). Omit to replay every type the endpoint receives.

## Response

### 202

Deliveries queued. `count` is the number of events that matched the endpoint and were queued (may be 0).

- `data` (ApiWebhooksWebhookIdReplayPostResponsesContentApplicationJsonSchemaData, required)

## Errors

### 400 Bad Request Error

The body is invalid, the range is reversed or older than 30 days, it contains more than 1000 events, or a type is not subscribable.

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 401 Unauthorized Error

No usable credential. Either the `Authorization` header is missing or is not a well-formed `Bearer jl_…` key, or the key is unknown, revoked or expired. Do not retry with the same key. See [Authentication](/authentication#401-unauthorized).

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 403 Forbidden Error

Role below admin, an API key without the `full` scope, or a suspended workspace. Without an active subscription the request is refused with `BILLING_ERROR` and `metadata.kind` = `subscription_required`.

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 404 Not Found Error

No webhook with this id in the workspace, it was deleted, or `webhookId` is not a UUID.

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 429 Too Many Requests Error

The configuration-mutations limit (10/min) or the general API limit was exceeded.

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

## Types

### ApiWebhooksWebhookIdReplayPostResponsesContentApplicationJsonSchemaData

- `count` (integer, required)

### ErrorResponseError

The error object. Always has `code` and `message`.

- `code` (string, required) — Stable machine-readable error code (for example `VALIDATION_FAILED`, `PAYLOAD_TOO_LARGE`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BILLING_ERROR`, `COMPLIANCE_BLOCKED`, `RATE_LIMIT_EXCEEDED`, `INTERNAL_ERROR`). Switch on this, not on `message`. See [Errors](/errors).
- `message` (string, required) — Human-readable explanation. English or Spanish depending on the route; may change without notice.
- `details` (ErrorResponseErrorDetails, optional) — Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields); * for a rejected multipart upload (file in an unexpected field, too many files), a list with the upload error `code` (for example `LIMIT_UNEXPECTED_FILE`) and the `field` name. Absent when the value was rejected outside the route's own validation: a malformed id, number or date the database could not read, or a JSON body that does not parse.
- `metadata` (map from string to any, optional) — Structured detail exposed for a small allowlist of codes only — for example `BILLING_ERROR` carries `limit`, `current` and `tier` (resource caps), `tier` alone (feature gates), or `tier` = `none` with `kind` = `subscription_required` when the workspace has no active subscription. See [Errors](/errors).

### ErrorResponseErrorDetails

Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields); * for a rejected multipart upload (file in an unexpected field, too many files), a list with the upload error `code` (for example `LIMIT_UNEXPECTED_FILE`) and the `field` name. Absent when the value was rejected outside the route's own validation: a malformed id, number or date the database could not read, or a JSON body that does not parse.

- Field map: Field map
- Issue list: list of ErrorResponseErrorDetailsOneOf1Items

### Field map

- `formErrors` (list of string, optional)
- `fieldErrors` (map from string to list of string, optional)

### ErrorResponseErrorDetailsOneOf1Items

- `path` (ErrorResponseErrorDetailsOneOf1ItemsPath, optional) — Dot-separated string, or an array of keys.
- `message` (string, optional)
- `code` (string, optional) — Zod issue code, for example `invalid_type`.

### ErrorResponseErrorDetailsOneOf1ItemsPath

Dot-separated string, or an array of keys.

- string
- list of ErrorResponseErrorDetailsOneOf1ItemsPathOneOf1Items

### ErrorResponseErrorDetailsOneOf1ItemsPathOneOf1Items

- string
- integer

## Examples

**Request**

```json
{
  "from": "2026-09-26T00:00:00Z",
  "to": "2026-09-27T12:00:00Z",
  "types": [
    "call.completed"
  ]
}
```

**Response**

```json
{
  "data": {
    "count": 42
  }
}
```

**SDK Code**

```python Webhooks_postWebhooksByWebhookIdReplay_example
import requests

url = "https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay"

payload = {
    "from": "2026-09-26T00:00:00Z",
    "to": "2026-09-27T12:00:00Z",
    "types": ["call.completed"]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Webhooks_postWebhooksByWebhookIdReplay_example
const url = 'https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"from":"2026-09-26T00:00:00Z","to":"2026-09-27T12:00:00Z","types":["call.completed"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Webhooks_postWebhooksByWebhookIdReplay_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay"

	payload := strings.NewReader("{\n  \"from\": \"2026-09-26T00:00:00Z\",\n  \"to\": \"2026-09-27T12:00:00Z\",\n  \"types\": [\n    \"call.completed\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Webhooks_postWebhooksByWebhookIdReplay_example
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"from\": \"2026-09-26T00:00:00Z\",\n  \"to\": \"2026-09-27T12:00:00Z\",\n  \"types\": [\n    \"call.completed\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Webhooks_postWebhooksByWebhookIdReplay_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"from\": \"2026-09-26T00:00:00Z\",\n  \"to\": \"2026-09-27T12:00:00Z\",\n  \"types\": [\n    \"call.completed\"\n  ]\n}")
  .asString();
```

```php Webhooks_postWebhooksByWebhookIdReplay_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay', [
  'body' => '{
  "from": "2026-09-26T00:00:00Z",
  "to": "2026-09-27T12:00:00Z",
  "types": [
    "call.completed"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Webhooks_postWebhooksByWebhookIdReplay_example
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"from\": \"2026-09-26T00:00:00Z\",\n  \"to\": \"2026-09-27T12:00:00Z\",\n  \"types\": [\n    \"call.completed\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Webhooks_postWebhooksByWebhookIdReplay_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "from": "2026-09-26T00:00:00Z",
  "to": "2026-09-27T12:00:00Z",
  "types": ["call.completed"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/webhooks/9a7b6c5d-4e3f-4a2b-8c1d-0e9f8a7b6c5d/replay")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```