Webhook Endpoints
Webhook Endpoints — methods, parameters, and examples for @easylabs/node.
Webhook endpoints are HTTPS URLs that receive event deliveries. Register up to 5 active endpoints per company, each subscribed to all events (["*"]) or a specific subset of EASY_EVENT_TYPES. The signing secret is returned only on creation — store it immediately.
For verifying inbound deliveries, see the top-level Webhooks page.
Methods
easy.registerWebhookEndpoint(body); // POST /webhooks
easy.listWebhookEndpoints(); // GET /webhooks
easy.updateWebhookEndpoint(endpointId, body); // PATCH /webhooks/:id
easy.deleteWebhookEndpoint(endpointId); // DELETE /webhooks/:id
easy.listWebhookDeliveries(query?); // GET /webhooks/deliveries
easy.listEndpointDeliveries(endpointId, query?); // GET /webhooks/:id/deliveriesRegister
const ep = await easy.registerWebhookEndpoint({
url: "https://api.example.com/webhooks/easy",
events: ["payment.created", "subscription.updated", "invoice.paid"], // or ["*"]
});
console.log(ep.data.id);
console.log(ep.data.secret); // <-- store this NOW; it's never returned againThe URL must be HTTPS and cannot resolve to private / loopback addresses. The maximum is 5 active endpoints per company.
List, update, delete
const all = await easy.listWebhookEndpoints();
await easy.updateWebhookEndpoint(ep.data.id, { active: false });
await easy.deleteWebhookEndpoint(ep.data.id);Inspect deliveries
listWebhookDeliveries is the cross-endpoint delivery log. listEndpointDeliveries(endpointId, query) is the same shape scoped to one endpoint (no endpoint_id or include_counts parameters there).
const deliveries = await easy.listWebhookDeliveries({
event_type: "invoice.payment_failed",
success: false,
created_after: "2026-04-01T00:00:00Z",
limit: 100,
include_counts: true,
});
console.log(deliveries.data.total, deliveries.data.event_counts, deliveries.data.failed_count);Object shape
RegisteredWebhookEndpoint extends WebhookEndpoint:
| Field | Type | Notes |
|---|---|---|
id | string | |
url | string | |
events | string[] | ["*"] or specific event types. |
active | boolean | |
status | "enabled" | "disabled" | string | |
consecutive_failures | number | Endpoints auto-disable after repeated 5xx. |
last_triggered_at | string | null | |
secret | string | Only on the create response. |
WebhookDelivery: id, endpoint_id, event_type, payload (WebhookEvent), attempt, attempt_number, status_code, response_code, response_body, response_body_hash, response_time, error, success, created_at, next_retry_at.
WebhookDeliveriesListQuery: event_type?, success?, attempt?, attempt_number?, created_after?, created_before?, endpoint_id?, limit?, offset?, include_counts?.
Examples
Bootstrap a fresh endpoint at deploy time
const all = await easy.listWebhookEndpoints();
const expectedUrl = `${process.env.PUBLIC_URL}/webhooks/easy`;
const existing = all.data.find((e) => e.url === expectedUrl);
if (!existing) {
const created = await easy.registerWebhookEndpoint({
url: expectedUrl,
events: ["*"],
});
// Persist created.data.secret in a secret manager — you can't read it back later.
process.env.EASY_WEBHOOK_SECRET = created.data.secret;
}Replay a failed delivery's payload locally
const failed = await easy.listEndpointDeliveries(endpointId, {
success: false,
limit: 1,
});
const delivery = failed.data.deliveries[0];
console.log(delivery.payload); // typed WebhookEventRotate an endpoint's URL
await easy.updateWebhookEndpoint(endpointId, {
url: "https://api.example.com/v2/webhooks/easy",
});Rotate the signing secret
There is no rotate-secret endpoint. Delete the old endpoint and register a new one to issue a fresh secret:
const replacement = await easy.registerWebhookEndpoint({
url: existing.url,
events: existing.events as any,
});
await easy.deleteWebhookEndpoint(existing.id);
// store replacement.data.secret