Docs Rivya AI

API Webhooks

Tạo endpoint webhook có chữ ký cho Rivya API, xác minh chữ ký delivery, kiểm tra các lần delivery và gửi sự kiện kiểm thử an toàn.

Đánh giá lần cuối vào 2026/05/11

Dùng API webhooks khi tích hợp của bạn cần Rivya thông báo cho server sau khi một generation của Public API đi đến trạng thái cuối.

Việc polling GET /api/v1/generations/{taskId} vẫn được hỗ trợ. Webhooks bổ sung callback có chữ ký cho các hệ thống production muốn nhận kết quả qua event delivery.

Scope bắt buộc

Quản lý webhook yêu cầu API key có scope:

webhooks:manage

Các key mới tạo trong Settings mặc định đã bao gồm scope này.

Tạo 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"]
  }'

Phản hồi chỉ bao gồm signing_secret một lần:

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

Hãy lưu toàn bộ secret trên server của bạn. Nếu làm mất, hãy gọi endpoint rotate và cập nhật receiver.

Quy tắc URL

Endpoint URL phải dùng HTTPS. Rivya từ chối URL có thông tin xác thực, fragment, tên localhost, địa chỉ mạng cục bộ, dải IP riêng, địa chỉ loopback và địa chỉ dành riêng.

Rivya luôn gửi:

  • POST
  • Content-Type: application/json
  • không có request header tùy chỉnh do người dùng kiểm soát
  • không tự động đi theo redirect
  • timeout delivery ngắn

Event

Các event type hiện tại:

  • generation.succeeded
  • generation.failed

Webhook payload dùng cùng public generation serializer như endpoint trạng thái.

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

Mỗi delivery bao gồm:

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 để ký:

${timestamp}.${rawBody}

Thuật toán:

HMAC-SHA256 with the endpoint signing secret

Từ chối request có timestamp quá cũ. Mức dung sai 5 phút là mặc định thực tế.

Xác minh bằng 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"));
}

Xác minh bằng 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)

Quản lý 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-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} sẽ vô hiệu hóa endpoint. Lệnh này không xóa lịch sử delivery.

Bản ghi delivery

Liệt kê các event gần đây:

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

Liệt kê các lần delivery cho một endpoint:

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

Bản ghi delivery bao gồm status, HTTP status, số lần thử, request id, duration, đoạn response đã cắt ngắn và các trường lỗi công khai.

Event kiểm thử

Gửi payload kiểm thử an toàn:

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

Event kiểm thử dùng webhook.test. Nó không tạo generation task, không tiêu thụ credits và không bao gồm URL kết quả thật.

Chính sách retry

Rivya xem HTTP 2xx là thành công.

Thất bại bao gồm lỗi mạng, timeout, phản hồi redirect và phản hồi không phải 2xx. Rivya retry tối đa 5 lần:

  • ngay lập tức
  • sau 1 phút
  • sau 5 phút
  • sau 30 phút
  • sau 2 giờ

Sau lần thử cuối cùng, event được đánh dấu là failed.

Lỗi webhook delivery không thay đổi trạng thái generation, credits, refund hoặc lịch sử task.

Checklist bảo mật

  • Xác minh chữ ký HMAC trước khi phân tích business logic.
  • Từ chối timestamp quá cũ.
  • Xử lý event kiểm thử tách biệt với event generation.
  • Không ghi log toàn bộ signing secret.
  • Chỉ trả về 2xx sau khi receiver của bạn đã chấp nhận event.
  • Giữ polling làm fallback để đối soát.

Trang liên quan

Mục lục