Settings and IntegrationsTechnical reference

Developer Webhook API and Delivery

Register ISPbills webhooks, verify HMAC signatures, and handle delivery retries safely

Get help
What this guide covers

Register ISPbills webhooks, verify HMAC signatures, and handle delivery retries safely

On this page

Webhooks let ISPbills send an event to your server instead of requiring your integration to poll the API. Webhook endpoint management is available through API v2 and the API Management screen.

For the operator-facing screen and a non-code overview, see Admin Webhook Setup.

Register an endpoint

Register a public URL with at least one event. The request field is events_json:

POST /api/v2/webhooks
Authorization: Bearer YOUR_V2_TOKEN
Accept: application/json
Content-Type: application/json

{
  "url": "https://integration.example.com/webhooks/ispbills",
  "events_json": ["customer.created", "payment.received"],
  "is_active": true
}

The create response includes a signing secret:

{
  "data": {
    "id": 17,
    "url": "https://integration.example.com/webhooks/ispbills",
    "events": ["customer.created", "payment.received"],
    "is_active": true,
    "created_at": "2026-08-16T12:00:00.000000Z"
  },
  "secret": "ONE_TIME_SIGNING_SECRET"
}

Store the secret immediately in your server-side secret manager. It is returned when the endpoint is created and is not included when endpoints are listed.

Management endpoints

Method Endpoint Description
GET /api/v2/webhooks List endpoint IDs, URLs, event subscriptions, active state, and creation time
POST /api/v2/webhooks Register an endpoint
PUT /api/v2/webhooks/{id} Update url, events_json, or is_active
DELETE /api/v2/webhooks/{id} Delete an endpoint

All records are restricted to the authenticated API client’s operator.

Event names

The API Management screen currently offers these subscriptions:

Event Meaning
customer.created Customer created
customer.updated Customer details updated
customer.deleted Customer deleted
customer.suspended Customer suspended
customer.renewed Customer renewed
bill.created Bill created
invoice.generated Invoice generated
payment.received Payment recorded or confirmed
payment.failed Payment attempt failed
subscription.expired Subscription expired
* Subscribe to every dispatched event

Your receiver should safely ignore unknown event names. New event types can be introduced without changing the payload envelope.

Delivery request

ISPbills sends an HTTP POST with these headers:

Content-Type: application/json
X-Webhook-Event: customer.created
X-Webhook-Signature: sha256=HEX_HMAC_DIGEST

Payload envelope:

{
  "event": "customer.created",
  "timestamp": "2026-08-16T12:00:00.000000Z",
  "data": {
    "id": 1234,
    "name": "Example Customer",
    "status": "active"
  }
}

The contents of data depend on the event. Use event to choose a handler and tolerate additional fields.

Verify the signature

The signature is:

sha256=HMAC_SHA256(raw_request_body, webhook_secret)

Verify the exact raw bytes before decoding JSON. Do not parse and re-encode the body before calculating the HMAC.

PHP example:

$rawBody = file_get_contents('php://input');
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $webhookSecret);

if (! hash_equals($expected, $received)) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode($rawBody, true, flags: JSON_THROW_ON_ERROR);

Node.js example:

import crypto from 'node:crypto';

const expected = `sha256=${crypto
  .createHmac('sha256', process.env.ISPBILLS_WEBHOOK_SECRET)
  .update(rawBody)
  .digest('hex')}`;

const valid = crypto.timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(request.headers['x-webhook-signature'] || ''),
);

Check buffer lengths before timingSafeEqual in production because it throws when lengths differ.

Delivery and retries

Webhook delivery runs asynchronously. A failed delivery is attempted up to three times with increasing delays. The receiving endpoint should:

  1. Verify the signature.
  2. Store the event or enqueue local work.
  3. Return a 2xx response promptly.
  4. Process slow operations outside the HTTP request.

Delivery is at least once. A retry can deliver the same event more than once, so make handlers idempotent. A practical deduplication key combines the event name, relevant resource ID, and timestamp until a dedicated delivery ID is available.

Operational checklist

  • Use an HTTPS endpoint with a valid certificate.
  • Keep the signing secret outside application logs and source code.
  • Compare signatures with a timing-safe function.
  • Allow new JSON fields and unknown event names.
  • Monitor non-2xx responses and receiver latency.
  • Disable or delete an endpoint before retiring its receiver.
  • Rotate a compromised secret by replacing the webhook endpoint.
Need help applying this guide?Browse related guidance or ask the support team for help.