Webhooks
Subscribe to listing, offer, order, payment, and payout events.
Webhooks
Webhook endpoints let downstream systems react to marketplace changes without polling. The beta product keeps the event model intentionally close to the core REST resources so event consumers do not need a second mental model.
Core Routes
| Route | Purpose |
|---|---|
GET /api/v1/webhooks/endpoints | List endpoints for the active organization |
POST /api/v1/webhooks/endpoints | Create an endpoint and return the signing secret |
PATCH /api/v1/webhooks/endpoints/:id | Update url, events, description, or status |
DELETE /api/v1/webhooks/endpoints/:id | Remove an endpoint |
GET /api/v1/webhooks/deliveries | Inspect stored delivery attempts |
Endpoint create, update, and delete routes currently require a signed-in
owner, admin, or developer user for the active organization.
Event Types
listing.publishedoffer.submittedoffer.counteredoffer.acceptedoffer.rejectedorder.createdorder.paidorder.fulfilledorder.refundedorder.disputedpayment.succeededpayment.failedpayment.refundedpayout.released
Create An Endpoint
{
"url": "https://example.com/zenbid/webhooks",
"description": "Marketplace sync endpoint",
"subscribedEvents": ["order.created", "order.paid", "payout.released"]
}Endpoint creation returns both:
endpointsigningSecret
Store the signing secret immediately. ZenBid does not expose the raw secret again after creation.
Delivery Format
Each webhook request includes:
X-ZenBid-EventX-ZenBid-Event-IdX-ZenBid-TimestampX-ZenBid-Signature
The signature format is:
t=<unix-timestamp>,v1=<sha256-hmac>ZenBid signs the string <timestamp>.<raw-json-payload> with the endpoint's
signing secret.
Delivery Records
Each delivery stores:
- the event payload
- delivery status
- response status
- attempt count
- last attempt time
- next attempt time when delivery failed
That gives beta operators enough visibility to inspect failures and manage follow-up without polling live systems.
Signature Verification
import { verifyZenBidWebhookSignature } from "@zenbid/sdk";
const rawBody = await request.text();
const isValid = verifyZenBidWebhookSignature({
secret: process.env.ZENBID_WEBHOOK_SECRET!,
payload: rawBody,
signatureHeader: request.headers.get("x-zenbid-signature"),
});
if (!isValid) {
throw new Error("Invalid ZenBid webhook signature");
}