2xx status code, times out, or is unreachable — Raise retries the delivery. The webhook log endpoints expose retry history so partners can investigate, but the OpenAPI spec doesn’t document the specific retry schedule, the maximum number of attempts, the backoff strategy, or the timeout that triggers a retry.
This page covers what’s known from the log endpoints, what’s not in the spec, and the defensive patterns that partner integrations should use until the spec documents the retry contract explicitly.
What the spec confirms
Looking only at what’s documented:- The
WebhookLogListModelschema includessuccess(string),httpStatusCode(string), andserverResponse(string) fields — meaning Raise records the outcome of each delivery attempt. - Multiple log entries can exist for the same
contextId(the ID of the entity that triggered the event) — meaning Raise can attempt delivery more than once for the same event. - The log endpoints support pagination — meaning delivery history is retained for at least some retention window.
- How many retry attempts Raise makes per failed delivery
- How long Raise waits between attempts
- What status codes from the partner endpoint trigger retries vs. permanent failures
- How long Raise waits for a response before considering a delivery timed out
The retry-from-the-partner-perspective view
Even without spec-level retry details, partners can observe retries through the webhook logs. Multiple log entries with the samecontextId and different createdDate values indicate Raise retried the delivery.
Inspecting retry history for a specific event
cURL
httpStatusCode and success fields show whether each attempt eventually succeeded.
JavaScript
2xx status codes and the later one with 2xx.
Distinguishing “currently retrying” from “permanently failed”
If retries continue for an extended period — minutes to hours — the delivery is likely in an active retry loop. If no more retries appear after a sustained gap, Raise has likely given up on the delivery. Without a spec-documented retry schedule, the practical heuristic is:| Pattern | Likely state |
|---|---|
One entry, 2xx status | Delivered successfully on first attempt |
Multiple entries, final one 2xx | Delivered successfully after retries |
Multiple entries, all non-2xx, increasing time gaps | Likely still retrying |
Multiple entries, all non-2xx, no entries for several hours | Likely abandoned — needs investigation |
How the partner endpoint controls retry behavior
The partner endpoint’s HTTP response shapes what Raise does next. The general behavior most webhook systems use (which partners should assume Raise also follows until the spec confirms otherwise):| Partner response | Likely treated as |
|---|---|
200–299 | Success — no retry |
400 (Bad Request) | Permanent failure — no retry (Raise can’t fix a request the partner says is malformed) |
401 (Unauthorized) | Permanent or transient — depends on the implementation |
404 (Not Found) | Permanent — the endpoint is gone |
408 (Request Timeout), 429 (Too Many Requests) | Transient — retry expected |
500–599 | Transient — retry expected |
| Connection refused, DNS error | Transient — retry expected |
| No response within timeout | Transient — retry expected |
- If your endpoint received the request successfully and intends to process it, return
200 OKimmediately. Don’t wait for processing to complete before responding. - If your endpoint can’t accept the request right now (rate limited, in maintenance, etc.), return
503 Service Unavailableand Raise will retry later. - If the request is genuinely malformed (signature verification failed, body parsing failed), return
400or401— but make sure your endpoint really can’t handle the request, because Raise typically won’t retry these.
Don’t return 200 for failures
A tempting anti-pattern: return200 OK always, then log errors internally and hope someone notices. This breaks Raise’s retry mechanism — every delivery looks successful to Raise even when the partner actually failed to process it.
JavaScript
Idempotency is non-negotiable
Because Raise retries failed deliveries, the same event can arrive at the partner endpoint more than once. The partner side must handle duplicates safely — without producing duplicate side effects. See Idempotency and Safe Reprocessing for the patterns. The summary:- Identify each event uniquely (typically by
contextId+ event type, or by a delivery ID if available). - Track already-processed events in a deduplication store.
- Check the store before processing; skip if already processed.
- Update the store after successful processing.
Endpoint design that survives retries gracefully
A few patterns that make the partner endpoint robust against Raise’s retry behavior:Acknowledge quickly
Return200 OK within a few seconds. Most webhook systems use timeouts in the 10–30 second range; some shorter. An endpoint that takes 30 seconds to respond produces unnecessary retries even when the request is being handled correctly.
JavaScript
setImmediate (or equivalent in other frameworks) lets the response complete before processing begins.
Queue-based decoupling
A more robust pattern: use a message queue (SQS, Cloud Tasks, Redis-backed queue, etc.) between the webhook receiver and the event processor. Benefits:- The receiver is small and fast — it does only signature verification and enqueueing.
- Processing failures are handled by the queue’s retry mechanism, not by relying on Raise to retry.
- During traffic spikes, the queue absorbs load instead of overwhelming the processor.
Handle the timeout-but-succeeded edge case
A subtle issue: your endpoint processes the event successfully but is slow to respond. Raise times out, returns the delivery as failed, and retries. Your endpoint receives the same event a second time. Without idempotency, you’d process it twice. The defense:- Acknowledge quickly (as above) so timeouts are rare.
- Implement idempotency (the next page) so duplicate processing is harmless when retries do occur.
Investigating delivery problems
When the partner reports “we missed event X” or “we got the same event twice”:Look up the webhook log entries for the event
Use
GET /api/Webhook/{id}/log/list filtered to the relevant time range or context ID.Check the response codes
2xx on the final attempt = Raise considers it delivered. Non-2xx on the latest = Raise may still be retrying or have given up.Inspect the response bodies
serverResponse shows what the partner endpoint returned. A 200 OK with an error message in the body is a partner-side processing issue, not a delivery issue.Common scenarios
Scenario: partner endpoint was deployed during a maintenance window
If the partner endpoint was down for an hour during a deploy or outage, events that fired during that window arrived5xx from the unreachable endpoint. Raise retried those events.
What to do:
- Check the webhook logs after the partner endpoint is back up to confirm retries succeeded.
- If some retries are still failing after the partner endpoint is back, check whether Raise has given up on those specific events (no more log entries in the past hour).
- For permanently lost events, run a reconciliation pass to catch the missed records and process them through your normal ingestion path.
Scenario: signature verification was broken in a deploy
If a partner deployment introduced a signature verification bug, every incoming webhook returned401 Unauthorized. Raise may have stopped retrying these as permanent failures.
What to do:
- Fix the verification bug.
- Run a reconciliation pass to catch all events that were rejected during the window.
- Add an integration test for signature verification so this doesn’t recur.
Scenario: persistent 500 errors from the partner endpoint
The partner endpoint has been returning500 Internal Server Error for an extended period. Raise has likely been retrying with increasing delays and may have given up.
What to do:
- Identify and fix the root cause of the
5xxerrors. - After the fix, run a reconciliation pass to catch missed events. Don’t rely on Raise to retry events from days ago.
- Set up monitoring on the partner endpoint’s error rate to catch this faster next time.
Scenario: rate-limited at the partner endpoint
If the partner endpoint applies rate limiting and starts returning429 Too Many Requests, Raise’s retries may make the situation worse — backing off, then retrying, then being rate-limited again.
What to do:
- Raise the partner endpoint’s rate limit (this is a partner-side concern).
- Or, add a buffering queue in front so the partner can absorb bursts without rate-limiting Raise.
Monitoring webhook delivery health
For partner integrations operating in production, two metrics are worth tracking:| Metric | What it shows |
|---|---|
| Delivery success rate | The fraction of webhook log entries with success: "Yes" (or equivalent). Should be near 100%. |
| Time from event to processing complete | The end-to-end latency from when the underlying resource changed to when your processor finished handling the event. Spikes indicate a queue backlog or processor issue. |
JavaScript
The exact value of the
success field (string "Yes", "True", boolean, etc.) is not documented in the spec. Inspect actual log entries to confirm the value, and adjust the metric calculation accordingly.Where to go next
Idempotency and Safe Reprocessing
The companion pattern to retry handling — process duplicate deliveries safely.
Local Testing
Test the retry-and-acknowledge pattern locally before production.
Webhooks Overview
The full subscription lifecycle including log endpoint use.
Error Recovery Patterns
Broader patterns for handling failures across all of the partner integration.