API Webhooks
Create signed Rivya API webhook endpoints, verify delivery signatures, inspect delivery attempts, and send safe test events.
Last reviewed on 2026/05/11
Use API webhooks when your integration needs Rivya to notify your server after a Public API generation reaches a terminal state.
Polling GET /api/v1/generations/{taskId} is still supported. Webhooks add signed callbacks for production systems that prefer event delivery.
Required Scope
Webhook management requires an API key with:
webhooks:manageNew keys created in Settings include this scope by default.
Create Endpoint
POST /api/v1/webhookscurl https://rivya.ai/api/v1/webhooks \
-H "Authorization: Bearer rvya_sk_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Production webhook",
"url": "https://example.com/rivya/webhook",
"event_types": ["generation.succeeded", "generation.failed"]
}'The response includes signing_secret only once:
{
"id": "whend_...",
"object": "webhook_endpoint",
"name": "Production webhook",
"url": "https://example.com/rivya/webhook",
"event_types": ["generation.succeeded", "generation.failed"],
"status": "active",
"secret_preview": "whsec_12...abc123",
"signing_secret": "whsec_...",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"created_at": "2026-05-11T00:00:00.000Z",
"updated_at": "2026-05-11T00:00:00.000Z",
"disabled_at": null,
"revoked_at": null
}Store the full secret on your server. If you lose it, call the rotate endpoint and update your receiver.
URL Rules
Endpoint URLs must be HTTPS. Rivya rejects URLs with credentials, fragments, localhost names, local network addresses, private IP ranges, loopback addresses, and reserved addresses.
Rivya always sends:
POSTContent-Type: application/json- no custom user-controlled request headers
- no automatic redirect following
- a short delivery timeout
Events
Current event types:
generation.succeededgeneration.failed
Webhook payloads use the same public generation serializer as the status endpoint.
{
"id": "evt_...",
"type": "generation.succeeded",
"api_version": "2026-05-11",
"created_at": "2026-05-11T00:00:00.000Z",
"data": {
"generation": {
"id": "task_public_id",
"status": "succeeded",
"model": "z-image",
"reserved_credits": 1,
"final_credits": 1,
"created_at": "2026-05-11T00:00:00.000Z",
"updated_at": "2026-05-11T00:01:00.000Z",
"result": {
"primary_url": "https://...",
"urls": ["https://..."]
},
"error": null
}
}
}Delivery Headers
Each delivery includes:
Rivya-Webhook-Id: evt_...
Rivya-Webhook-Timestamp: 1778467200
Rivya-Webhook-Signature: v1=<hex-hmac-sha256>
Rivya-Webhook-Attempt: 1
Rivya-Webhook-Endpoint-Id: whend_...
Rivya-Request-Id: req_...Signature input:
${timestamp}.${rawBody}Algorithm:
HMAC-SHA256 with the endpoint signing secretReject requests with stale timestamps. A five-minute tolerance is a practical default.
JavaScript Verification
import crypto from "node:crypto";
function verifyRivyaWebhook({ rawBody, headers, signingSecret }) {
const timestamp = headers["rivya-webhook-timestamp"];
const signature = headers["rivya-webhook-signature"] || "";
const actual = signature.split(",").find((part) => part.startsWith("v1="))?.slice(3);
const expected = crypto
.createHmac("sha256", signingSecret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
if (!actual) return false;
return crypto.timingSafeEqual(Buffer.from(actual, "hex"), Buffer.from(expected, "hex"));
}Python Verification
import hmac
import hashlib
def verify_rivya_webhook(raw_body: str, headers: dict, signing_secret: str) -> bool:
timestamp = headers.get("rivya-webhook-timestamp", "")
signature = headers.get("rivya-webhook-signature", "")
actual = next((part[3:] for part in signature.split(",") if part.startswith("v1=")), "")
expected = hmac.new(
signing_secret.encode(),
f"{timestamp}.{raw_body}".encode(),
hashlib.sha256,
).hexdigest()
return bool(actual) and hmac.compare_digest(actual, expected)Manage Endpoints
GET /api/v1/webhooks
GET /api/v1/webhooks/{endpointId}
PATCH /api/v1/webhooks/{endpointId}
DELETE /api/v1/webhooks/{endpointId}
POST /api/v1/webhooks/{endpointId}/rotate-secretcurl https://rivya.ai/api/v1/webhooks \
-H "Authorization: Bearer rvya_sk_..."
curl https://rivya.ai/api/v1/webhooks/whend_... \
-H "Authorization: Bearer rvya_sk_..."
curl -X PATCH https://rivya.ai/api/v1/webhooks/whend_... \
-H "Authorization: Bearer rvya_sk_..." \
-H "Content-Type: application/json" \
-d '{"status":"disabled"}'
curl -X POST https://rivya.ai/api/v1/webhooks/whend_.../rotate-secret \
-H "Authorization: Bearer rvya_sk_..."DELETE /api/v1/webhooks/{endpointId} disables the endpoint. It does not delete delivery history.
Delivery Records
List recent events:
GET /api/v1/webhook-eventscurl https://rivya.ai/api/v1/webhook-events \
-H "Authorization: Bearer rvya_sk_..."List delivery attempts for an endpoint:
GET /api/v1/webhooks/{endpointId}/deliveriescurl https://rivya.ai/api/v1/webhooks/whend_.../deliveries \
-H "Authorization: Bearer rvya_sk_..."Delivery records include status, HTTP status, attempt number, request id, duration, truncated response snippet, and public error fields.
Test Event
Send a safe test payload:
POST /api/v1/webhooks/{endpointId}/testcurl -X POST https://rivya.ai/api/v1/webhooks/whend_.../test \
-H "Authorization: Bearer rvya_sk_..."The test event uses webhook.test. It does not create a generation task, does not consume credits, and does not include a real result URL.
Retry Policy
Rivya treats HTTP 2xx as success.
Failures include network errors, timeout, redirect responses, and non-2xx responses. Rivya retries up to five attempts:
- immediately
- after 1 minute
- after 5 minutes
- after 30 minutes
- after 2 hours
After the final attempt, the event is marked failed.
Webhook delivery failures do not change generation status, credits, refunds, or task history.
Security Checklist
- Verify the HMAC signature before parsing business logic.
- Reject stale timestamps.
- Treat test events separately from generation events.
- Do not log full signing secrets.
- Return
2xxonly after your receiver has accepted the event. - Keep polling as a fallback for reconciliation.
Related Pages
Rivya TypeScript SDK
Use the Rivya TypeScript SDK beta to call Public API v1 for models, generations, files, credits, webhooks, and Chat including SSE streaming.
Rivya API Overview
Use Rivya API v1 to call Rivya generation and chat models from your own product with API keys, account credits, and optional SSE streaming.