Developers
Outbound Webhooks
FinkMesh can deliver signed platform events to your HTTPS endpoints. This page covers outbound platform webhooks. Inbound workflow webhooks are separate workflow trigger URLs that receive events from your apps.
Inbound Workflow Webhooks
Your app sends an event to a workflow trigger URL. The workflow receives the payload and runs after plan, readiness, quota, and rate-limit checks.
Outbound Platform Webhooks
FinkMesh sends platform events such as run completion, failures, auto-pauses, and support tickets to your app. This surface is beta and signed by endpoint secret.
Delivery Contract
POST https://your-app.example/webhooks/finkmesh Content-Type: application/json User-Agent: FinkMesh-Webhooks/1.0 FinkMesh-Event-Id: evt_... FinkMesh-Event-Type: workflow.run.completed FinkMesh-Timestamp: 1782950000 FinkMesh-Signature: v1=...
Signature
Verify FinkMesh-Signature with HMAC-SHA256 using the endpoint secret. The signed payload is timestamp.eventId.rawBody. Reject timestamps outside a five-minute tolerance to limit replay windows. Rotate secrets from Settings or the API when a receiver changes ownership.
Verify against the exact raw body bytes received by your server. Do not parse JSON and stringify it again before verification.
Event Envelope
{
"id": "evt_...",
"type": "workflow.run.completed",
"apiVersion": "2026-07-01",
"createdAt": "2026-07-01T12:00:00.000Z",
"workspaceId": "wsp_...",
"data": {
"object": {
"runId": "run_...",
"workflowId": "wf_...",
"status": "success"
}
}
}Treat id as the idempotency key in your receiver. Store processed event ids and ignore duplicates.
Verify Signatures In Node
import crypto from "node:crypto";
export function verifyFinkMeshWebhook({
secret,
timestamp,
eventId,
rawBody,
signature,
}: {
secret: string;
timestamp: string;
eventId: string;
rawBody: string;
signature: string;
}) {
const timestampSeconds = Number(timestamp);
if (!Number.isFinite(timestampSeconds)) return false;
const ageSeconds = Math.abs(Date.now() / 1000 - timestampSeconds);
if (ageSeconds > 5 * 60) return false;
const payload = `${timestamp}.${eventId}.${rawBody}`;
const expected = "v1=" + crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
const expectedBuffer = Buffer.from(expected);
const actualBuffer = Buffer.from(signature);
if (expectedBuffer.length !== actualBuffer.length) {
return false;
}
return crypto.timingSafeEqual(expectedBuffer, actualBuffer);
}Events
workflow.run.completed | A workflow run finished successfully. |
workflow.run.failed | A workflow run ended with an error. |
workflow.run.blocked | A workflow run was blocked by readiness, quota, or guardrails. |
workflow.auto_paused | A workflow was automatically paused by an error guardrail. |
connection.disconnected | A workspace connection needs attention. |
support.ticket.created | A support ticket was created for the workspace. |
Delivery Behavior
Operations
GET /api/v1/webhook-endpointsPOST /api/v1/webhook-endpointsPATCH /api/v1/webhook-endpoints/{endpointId}DELETE /api/v1/webhook-endpoints/{endpointId}POST /api/v1/webhook-endpoints/{endpointId}/testPOST /api/v1/webhook-endpoints/{endpointId}/rotate-secretGET /api/v1/webhook-endpoints/{endpointId}/deliveriesPOST /api/v1/webhook-deliveries/{deliveryId}/retry