Docs Rivya AI

API Webhooks

Buat endpoint webhook Rivya API bertanda tangan, verifikasi signature delivery, periksa percobaan delivery, dan kirim event test yang aman.

Terakhir ditinjau pada 2026/05/11

Gunakan API webhooks saat integrasi Anda membutuhkan Rivya untuk memberi tahu server Anda setelah generasi Public API mencapai status terminal.

Polling GET /api/v1/generations/{taskId} tetap didukung. Webhooks menambahkan callback bertanda tangan untuk sistem production yang lebih memilih delivery event.

Scope yang Dibutuhkan

Pengelolaan webhook membutuhkan API key dengan:

webhooks:manage

Key baru yang dibuat di Settings menyertakan scope ini secara default.

Membuat Endpoint

POST /api/v1/webhooks
curl 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"]
  }'

Respons menyertakan signing_secret hanya satu kali:

{
  "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
}

Simpan secret lengkap di server Anda. Jika hilang, panggil endpoint rotate dan perbarui receiver Anda.

Aturan URL

URL endpoint harus HTTPS. Rivya menolak URL dengan credentials, fragments, nama localhost, alamat jaringan lokal, rentang IP privat, alamat loopback, dan alamat reserved.

Rivya selalu mengirim:

  • POST
  • Content-Type: application/json
  • tidak ada custom request headers yang dikendalikan pengguna
  • tidak mengikuti redirect otomatis
  • timeout delivery yang singkat

Event

Jenis event saat ini:

  • generation.succeeded
  • generation.failed

Payload webhook memakai serializer generasi publik yang sama dengan endpoint status.

{
  "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
    }
  }
}

Header Delivery

Setiap delivery menyertakan:

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_...

Input signature:

${timestamp}.${rawBody}

Algoritma:

HMAC-SHA256 with the endpoint signing secret

Tolak request dengan timestamp lama. Toleransi lima menit adalah default praktis.

Verifikasi JavaScript

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"));
}

Verifikasi Python

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)

Mengelola Endpoint

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-secret
curl 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} menonaktifkan endpoint. Ini tidak menghapus riwayat delivery.

Record Delivery

Daftar event terbaru:

GET /api/v1/webhook-events
curl https://rivya.ai/api/v1/webhook-events \
  -H "Authorization: Bearer rvya_sk_..."

Daftar percobaan delivery untuk endpoint:

GET /api/v1/webhooks/{endpointId}/deliveries
curl https://rivya.ai/api/v1/webhooks/whend_.../deliveries \
  -H "Authorization: Bearer rvya_sk_..."

Record delivery menyertakan status, HTTP status, attempt number, request id, duration, snippet respons yang dipotong, dan field error publik.

Event Test

Kirim payload test yang aman:

POST /api/v1/webhooks/{endpointId}/test
curl -X POST https://rivya.ai/api/v1/webhooks/whend_.../test \
  -H "Authorization: Bearer rvya_sk_..."

Event test memakai webhook.test. Event ini tidak membuat tugas generasi, tidak memakai credits, dan tidak menyertakan URL hasil nyata.

Kebijakan Retry

Rivya memperlakukan HTTP 2xx sebagai sukses.

Kegagalan mencakup error jaringan, timeout, respons redirect, dan respons non-2xx. Rivya mencoba ulang hingga lima kali:

  • segera
  • setelah 1 menit
  • setelah 5 menit
  • setelah 30 menit
  • setelah 2 jam

Setelah percobaan terakhir, event ditandai failed.

Kegagalan delivery webhook tidak mengubah status generasi, credits, refund, atau riwayat tugas.

Checklist Keamanan

  • Verifikasi signature HMAC sebelum memproses logika bisnis.
  • Tolak timestamp lama.
  • Perlakukan event test secara terpisah dari event generasi.
  • Jangan mencatat signing secret lengkap.
  • Kembalikan 2xx hanya setelah receiver Anda menerima event.
  • Pertahankan polling sebagai fallback untuk rekonsiliasi.

Halaman Terkait

Daftar Isi