// Outbound webhook helpers. // Backend: /api/v1/webhooks (CRUD + pause/resume/regenerate-secret/deliveries/stats/test). import type { ArcadiaClient } from "@crema/arcadia-client" export type WebhookStatus = "active" | "paused" | "disabled" export type WebhookRetryStrategy = "linear" | "exponential" export interface Webhook { id: string tenant_id: string url: string description: string | null status: WebhookStatus events: string[] headers: Record max_retries: number retry_strategy: WebhookRetryStrategy last_triggered_at: string | null success_count: number failure_count: number /** Only populated on create / regenerate-secret responses. */ secret?: string | null inserted_at: string updated_at: string } export interface WebhookInput { url: string description?: string | null events?: string[] headers?: Record max_retries?: number retry_strategy?: WebhookRetryStrategy } export interface WebhookDelivery { id: string webhook_endpoint_id: string event_type: string status: "pending" | "delivered" | "failed" | string attempt: number request_url: string request_headers: Record response_status: number | null response_time_ms: number | null error_message: string | null sent_at: string | null completed_at: string | null next_retry_at: string | null inserted_at: string } export interface WebhookStats { success_rate: number delivery_count: number failure_count: number avg_response_time_ms: number [key: string]: unknown } export async function listWebhooks(arcadia: ArcadiaClient): Promise { const res = await arcadia.GET<{ data: Webhook[] }>("/api/v1/webhooks") return res.data } export async function getWebhook(arcadia: ArcadiaClient, id: string): Promise { const res = await arcadia.GET<{ data: Webhook }>(`/api/v1/webhooks/${id}`) return res.data } export async function createWebhook( arcadia: ArcadiaClient, input: WebhookInput, ): Promise { const res = await arcadia.POST<{ data: Webhook }>("/api/v1/webhooks", { body: { webhook_endpoint: input }, }) return res.data } export async function updateWebhook( arcadia: ArcadiaClient, id: string, input: Partial, ): Promise { const res = await arcadia.PATCH<{ data: Webhook }>(`/api/v1/webhooks/${id}`, { body: { webhook_endpoint: input }, }) return res.data } export async function deleteWebhook(arcadia: ArcadiaClient, id: string): Promise { await arcadia.DELETE(`/api/v1/webhooks/${id}`) } export async function pauseWebhook(arcadia: ArcadiaClient, id: string): Promise { const res = await arcadia.POST<{ data: Webhook }>(`/api/v1/webhooks/${id}/pause`) return res.data } export async function resumeWebhook(arcadia: ArcadiaClient, id: string): Promise { const res = await arcadia.POST<{ data: Webhook }>(`/api/v1/webhooks/${id}/resume`) return res.data } export async function regenerateWebhookSecret( arcadia: ArcadiaClient, id: string, ): Promise { const res = await arcadia.POST<{ data: Webhook }>( `/api/v1/webhooks/${id}/regenerate-secret`, ) return res.data } export async function listWebhookDeliveries( arcadia: ArcadiaClient, id: string, params?: { limit?: number; offset?: number }, ): Promise { const res = await arcadia.GET<{ data: WebhookDelivery[] }>( `/api/v1/webhooks/${id}/deliveries`, { params: params as Record }, ) return res.data } export async function getWebhookStats( arcadia: ArcadiaClient, id: string, ): Promise { const res = await arcadia.GET<{ data: WebhookStats }>( `/api/v1/webhooks/${id}/stats`, ) return res.data } export async function testWebhook( arcadia: ArcadiaClient, id: string, ): Promise<{ ok: boolean; message?: string; details?: unknown }> { return arcadia.POST(`/api/v1/webhooks/${id}/test`) } // A starter list of platform events. Free-form by design — different deployments // emit different events. Users can type custom values. export const COMMON_WEBHOOK_EVENTS = [ "user.created", "user.updated", "user.deleted", "tenant.created", "tenant.updated", "object.uploaded", "object.deleted", "secret.rotated", "invitation.sent", "invitation.accepted", "scheduled_task.completed", "scheduled_task.failed", ]