Set up a webhook
Build a receiver for Cevoid webhooks, create a webhook destination for it and pick the events it receives, or send to it from a Flow.
A webhook needs a receiver on your side and a destination in Cevoid that points at it. The destination receives the events you pick, and any a Flow sends to it.
Prerequisites
- You can open Settings → Developers → Webhooks in your Cevoid workspace, as an active team member.
- You have a public HTTPS URL for your receiver. Cevoid cannot reach
localhost; during development, expose your machine through a tunnel service.
Build the receiver
Your receiver accepts a POST, verifies the signature against the exact raw body, records the event and answers with a 2xx status within 10 seconds. Do slow work after you respond, for example in a job queue.
These receivers use the Standard Webhooks library (npm install standardwebhooks) to check the signature:
// app/webhooks/cevoid/route.ts
import { Webhook } from "standardwebhooks"
const webhook = new Webhook(process.env.CEVOID_WEBHOOK_SECRET ?? "")
export async function POST(request: Request) {
// The raw body: parsing and re-serializing JSON breaks the signature.
const body = await request.text()
try {
webhook.verify(body, Object.fromEntries(request.headers))
} catch {
return new Response("Invalid signature", { status: 401 })
}
const event = JSON.parse(body)
// Your own storage: skip an event ID you have already processed.
if (await alreadyProcessed(event.id)) return new Response(null, { status: 204 })
switch (event.type) {
case "product-review.submitted":
await copyReview(event.data.product_review)
break
}
return new Response(null, { status: 204 })
}import express from "express"
import { Webhook } from "standardwebhooks"
const app = express()
const webhook = new Webhook(process.env.CEVOID_WEBHOOK_SECRET)
// express.raw keeps the body as bytes for the signature check.
app.post("/webhooks/cevoid", express.raw({ type: "application/json" }), async (req, res) => {
const body = req.body.toString("utf8")
try {
webhook.verify(body, req.headers)
} catch {
return res.status(401).send("Invalid signature")
}
const event = JSON.parse(body)
// Your own storage: skip an event ID you have already processed.
if (await alreadyProcessed(event.id)) return res.sendStatus(204)
if (event.type === "product-review.submitted") await copyReview(event.data.product_review)
res.sendStatus(204)
})Answer a bad signature with 401: Cevoid stops retrying, and once your secret is fixed you can retry the delivery. Other 4xx statuses stop the delivery for good; see How Cevoid reads your response.
Create a destination
- Go to Settings → Developers → Webhooks and choose Create destination.
- Keep the type Events. Enter a name, your receiver's HTTPS URL as the endpoint URL and, if you like, a description.
- Under Events, pick the events the destination receives, such as
product-review.submittedorpost.approved. Search by name, or tick a whole group. To receive every event, including event types added later, tick All events instead. - Choose Create destination. Result: the signing secret is shown.
- Copy the signing secret, store it where your receiver reads it (for example
CEVOID_WEBHOOK_SECRET) and choose Done. You can reveal it again from the destination's details.
From now on, each event you picked is delivered to your receiver as it happens. To change the events later, open the destination and choose Edit destination.
Before you rely on it, test the webhook with a real signed event.
Manage webhooks with the API
Everything above also works through the API, with a secret key that has the webhooks:read or webhooks:write scope. Webhooks have whk_ IDs, and the Webhooks reference lists every operation.
curl -X POST https://api.cevoid.com/v2/webhooks \
-H "Authorization: Bearer $CEVOID_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "CRM", "url": "https://example.com/webhooks/cevoid", "events": ["product-review.submitted", "post.approved"]}'eventstakes event types, or["*"]for every event, including ones added later. A type that webhooks cannot receive, such as an order event or one only a Flow sends, returns422and nothing is saved.- The response to a create holds the signing secret once. To get a new one, rotate it; the previous secret also signs for 24 hours.
- Send a test event with
POST /v2/webhooks/{id}/test, list a webhook's events withGET /v2/webhooks/{id}/eventsand replay one withPOST /v2/webhooks/{id}/events/{event_id}/replay. A replay keeps the event'sid. Both sends take anIdempotency-Keyheader, and the webhook must be active. - Event history is keyed by the
evt_ID your receiver gets asidandwebhook-id. - The API manages
Eventsdestinations only.
Send from a Flow
Use a Flow when you need more than the event itself: send only some events with a filter, wait before sending, or send a review or upload request, such as product-review-request.created, which only a Flow's request actions create.
In a Flow, add an Action step, set Delivery target to Webhook and choose a destination in Webhook destination, or Create destination there. Preview payload on the step shows the data it sends. Publish the Flow to start sending.
A destination that subscribes to an event and also gets it from a Flow receives it twice, as two deliveries with different IDs. The destination's event list marks such events Also sent by a Flow. To receive each event once, either unpick it on the destination or remove the Flow's webhook step. Only the Flow's copy carries origin.
URL requirements
Cevoid checks the URL when you save the destination and again before every attempt:
- It must use HTTPS and resolve only to public addresses. Private, loopback and other reserved ranges are rejected, and so are host names such as
localhostand names ending in.local,.internal,.localhostor.home.arpa. - It must use a host name, not an IP address.
- It cannot contain credentials, a query string or a fragment.
- Ports 22, 23, 25, 110 and 143 are blocked.
Cevoid connects to the address it checked and does not follow redirects, so point the destination at the final URL.
Manage destinations
Destinations are listed in Settings → Developers → Webhooks. Open one to see its details and its Event deliveries.
- Edit destination: the name, URL, description and events. A new URL applies to deliveries that have not made their first attempt yet; retries keep the URL of the first attempt.
The menu of each destination has:
- Send test: a signed
cevoid.testevent. See Test a webhook. - Rotate secret and Finish secret rotation: see Rotate the signing secret.
- Disable and Enable: Cevoid sends nothing to a disabled destination; its pending deliveries stop instead. A delivery that stopped between retries can be retried once you enable the destination again.
- Archive: hides the destination for good. It is refused while any Flow, published or draft, still uses the destination.