Skip to main content
Support & Technical Documentation

NBN® webhooks - event list, payload, signature and IP addresses to allow

NBN documentation and configuration reference.

Loading documentation...
Markdown

Every NBN® webhook event with example JSON payloads and headers, how to verify the signature, retries, and the IP addresses to allow in your firewall for NBN® webhooks.

NBN® webhooks send an update to your own system, Slack, Microsoft Teams, Discord or Google Chat whenever something happens on your NBN® internet: an order is connected, a technician appointment is booked, a speed plan changes, there is an outage, or a charge or credit is applied. This guide lists every webhook event, shows the payload and headers we send, how to check the signature, and the IP addresses webhooks come from.

New to webhooks? Start with NBN® text messages and webhooks to add one in My Account, then come back here for the technical detail.

IP addresses webhooks come from

NBN® webhooks are sent from either of our two Australian data centres. If your firewall only lets in known addresses, allow both:

Data centreIP address
Melbourne103.140.134.210
Sydney103.137.56.120
  • Webhooks are sent over IPv4 only.
  • Either address can send any update, including a test, so allow both rather than just one.
  • Every request has the user agent Crazytel-NBN-Webhooks/1.

Your webhook address

  • It must start with https:// and have a valid certificate for its host name.
  • It must be reachable from the internet. Private or local addresses (such as localhost, 10.x.x.x or 192.168.x.x) are refused, and we check this every time we send.
  • Do not put a username or password in the address. Use a custom header instead (see Options and limits).
  • We never follow redirects. Use the final address your server answers on.
  • You can add a backup address. If the main address cannot be reached, we try the backup straight away.

Events you can choose

Choose single events, a whole group (for example nbn.order.* for every order update), or * for everything.

EventWhen it is sent
Orders (nbn.order.*)
nbn.order.submittedYour new connection or transfer was sent to the NBN® network.
nbn.order.processingThe NBN® network accepted your order and is working on it.
nbn.order.completedYour connection is active, or your transfer to Crazytel is done.
nbn.order.failedThe NBN® network could not complete the order.
nbn.order.cancelledThe order was cancelled before it was completed.
Appointments (nbn.appointment.*)
nbn.appointment.bookedA technician appointment was booked.
nbn.appointment.rescheduledA technician appointment was changed.
Speed plans (nbn.plan.*)
nbn.plan.change_requestedA speed plan change was requested.
nbn.plan.changedThe new speed plan is active.
nbn.plan.change_failedThe speed plan could not be changed. The service stays on its old plan.
nbn.plan.migration_scheduledWe have told you your plan will change on a set date. Includes the date, the new price and a link to the new Critical Information Summary.
Your service (nbn.service.*)
nbn.service.suspendedThe service was suspended.
nbn.service.reactivatedThe service was turned back on.
nbn.service.disconnection_requestedA disconnection was requested.
nbn.service.disconnectedThe service was disconnected or permanently removed.
nbn.service.transferred_outThe service moved to another provider.
nbn.service.settings_updatedService settings were updated.
nbn.service.ip_assignment_change_requestedA change between a dynamic and a static IP address was requested.
nbn.service.ip_assignment_changedThe IP address change is done.
nbn.service.ip_assignment_change_failedThe IP address change could not be made. The service keeps its previous setting.
Billing (nbn.billing.*)
nbn.billing.charge_appliedA charge for your NBN® service was taken from your prepaid balance.
nbn.billing.credit_appliedA credit for your NBN® service was added.
nbn.billing.prepaid_debit_warningYour prepaid account is in debit and the service is being suspended. Includes the deadline and how much to top up.
Checks (nbn.diagnostics.*)
nbn.diagnostics.completedA line test or service health check finished.
Network (nbn.network.*)
nbn.network.outageThe NBN® network reported an outage that may affect your service.
nbn.network.outage_resolvedThe NBN® network cleared the outage.
Test
nbn.webhook.pingOnly sent when you send a test. It is never included by *.

You can also choose which connections a webhook covers: all of them, one connection, or a selection (by connection, by connection type such as FTTP, or by words in the connection's name or your own reference).

What we send

Each update is one HTTP POST with a JSON body (Content-Type: application/json).

Headers

HeaderWhat it is
X-Crazytel-EventThe event, for example nbn.order.completed.
X-Crazytel-Event-IdThe event's id. The same as id in the body, and it never changes, even when the event is sent again.
X-Crazytel-Event-Version1 the first time. Goes up by one each time you ask for the event to be sent again.
X-Crazytel-DeliveryA new id for every single attempt. Quote it if you contact support about a delivery.
X-Crazytel-TimestampWhen this attempt was sent, in Unix seconds.
X-Crazytel-Signature-256The signature, for example t=1793755800,v1=5f2b....
X-Crazytel-Replaytrue when you asked for the event to be sent again. Left out otherwise.
User-AgentCrazytel-NBN-Webhooks/1

Any custom headers you added are sent as well.

The JSON body

Every event has the same outer layout:

FieldWhat it is
idThe event id. Use it to spot duplicates.
typeThe event, for example nbn.plan.changed.
api_versionThe layout version, currently 2026-10-27.
created_atWhen the event happened, in UTC (ends in Z).
account_codeYour Crazytel account.
sequenceA counter for the connection. A bigger number is a newer state; use it to put updates for one connection in order.
data.serviceThe connection: service_uuid (our id for it), avc_id (the NBN® service id), technology (FTTP, FTTC, FTTN, FTTB, HFC or Fixed Wireless), tenure_number, service_status and address.
data.titleA short heading, for example NBN Connection Activated.
data.messageA plain sentence you can show to people.
data.action, data.phaseWhat happened, for example new_connection and completed. Sent with most events.
data.operation_uuidOur id for the request this event belongs to, when there is one.
data.billingCharge or credit details, when the event has them (see below).
data.testtrue on a test event. Not sent on real events.

Example: a new connection is active.

{
  "account_code": "0123456789",
  "api_version": "2026-10-27",
  "created_at": "2026-11-04T01:30:00Z",
  "data": {
    "action": "new_connection",
    "message": "Good news, your NBN connection is now active.",
    "operation_uuid": "7d3c1a52-0b4e-4f7a-9a51-2f6a1c9e8b10",
    "phase": "completed",
    "service": {
      "address": "1 Example Street, Sampleton QLD 4000",
      "avc_id": "AVC000000000000",
      "service_status": "ACTIVE",
      "service_uuid": "00000000-0000-4000-8000-000000000000",
      "technology": "FTTP",
      "tenure_number": 1
    },
    "title": "NBN Connection Activated"
  },
  "id": "evt_00000000000000000000000000",
  "sequence": 3,
  "type": "nbn.order.completed"
}

We send the body on a single line with no spaces. It is shown spread out here so it is easier to read.

Billing details

nbn.billing.charge_applied and nbn.billing.credit_applied include a billing block. Amounts are in Australian dollars and include GST.

"billing": {
  "entry_id": 48211,
  "entry_type": "debit",
  "component": "base",
  "component_label": "Speed plan",
  "reason": "activation_pro_rata",
  "reason_label": "First part month",
  "description": null,
  "amount": "24.50",
  "currency": "AUD",
  "amounts_include_gst": true,
  "period_start_date": "2026-10-15",
  "period_end_date": "2026-10-31",
  "settled_at": "2026-10-15T03:12:44Z"
}

entry_type is debit for a charge and credit for a credit. Use entry_id to match an update to the charge in Usage & Billing.

Extra fields on some events

nbn.plan.migration_scheduled
effective_date, new_price_inc_gst, cis_url (the new Critical Information Summary) and campaign_uuid.
nbn.billing.prepaid_debit_warning
deadline (UTC) and top_up_needed (dollars, GST included).
nbn.service.reactivated, nbn.service.disconnected
When this is about your prepaid balance, reason is payment_received or non_payment.
nbn.diagnostics.completed
A check block with kind (line_check or health_check), label and reference. data.message says how it went.

Slack, Microsoft Teams, Discord and Google Chat

When you pick a chat layout, we post one readable line instead of the full JSON, made from the title and message:

Slack, Teams, Google Chat:  {"text":"NBN Connection Activated - Good news, your NBN connection is now active."}
Discord:                    {"content":"NBN Connection Activated - Good news, your NBN connection is now active."}

The headers and signature are the same for every layout.

Leave out the address or billing

Each webhook has two switches, both on to start with:

  • Include the service address: turn off to leave data.service.address out.
  • Include billing details: turn off to leave the billing block out.

Check the signature

When you add a webhook we show you a signing secret once. It starts with whsec_. Save it somewhere safe: we cannot show it again. If you lose it, make a new one.

The X-Crazytel-Signature-256 header looks like t=<timestamp>,v1=<signature>. To check it:

  1. Read the raw body exactly as it arrived, before you parse it.
  2. Join the t value, a full stop, and the raw body: <t>.<body>.
  3. Work out the HMAC-SHA256 of that text with your secret, as lowercase hexadecimal.
  4. Accept the update if it matches any v1 value. Reject it if it matches none, or if t is more than 5 minutes from your clock.

Example: Python

import hashlib, hmac, time

def is_from_crazytel(raw_body: bytes, signature_header: str, secret: str) -> bool:
    parts = [p.split("=", 1) for p in signature_header.split(",") if "=" in p]
    stamp = next((v for k, v in parts if k == "t"), "")
    sent = [v for k, v in parts if k == "v1"]
    if not stamp.isdigit() or abs(time.time() - int(stamp)) > 300:
        return False
    expected = hmac.new(secret.encode(), stamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(expected, s) for s in sent)

Example: Node.js

const crypto = require('crypto');

function isFromCrazytel(rawBody, signatureHeader, secret) {
  const parts = signatureHeader.split(',').map(p => p.split('='));
  const stamp = (parts.find(([k]) => k === 't') || [])[1];
  const sent = parts.filter(([k]) => k === 'v1').map(([, v]) => v);
  if (!stamp || Math.abs(Date.now() / 1000 - Number(stamp)) > 300) return false;
  const expected = crypto.createHmac('sha256', secret)
    .update(`${stamp}.${rawBody}`).digest('hex');
  return sent.some(s => s.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}

Replying, retries and duplicates

What your server should reply

  • Reply with any 2xx status (such as 200 or 204) as soon as you have the update. Do slow work afterwards.
  • We wait up to 5 seconds to connect and 10 seconds for your reply. Slower than that counts as a failed attempt.
  • A 3xx redirect, 4xx or 5xx reply counts as failed. A 4xx from your main address means your server refused it, so we do not try the backup address for that attempt.

When we try again

Each update gets 6 tries to start with (you can choose 1 to 10). After a failed try we wait, then try again:

After tryWe wait about
115 seconds
21 minute
35 minutes
430 minutes
52 hours
6 and later6 hours
  • Waits vary by up to 20% so retries do not all arrive at once.
  • If your server sends a Retry-After header (for example with a 429), we wait at least that long, up to 6 hours.
  • After the last try the update shows as Failed, gave up in the Delivery log. You can press Send again on it at any time.
  • If 15 updates in a row fail, the webhook pauses for an hour. If 50 in a row fail, we switch it off and email you. Fix your server, turn the webhook back on, then send the missed updates again.

Duplicates and order

  • An update can occasionally arrive more than once. Use id (or X-Crazytel-Event-Id) to ignore one you have already handled.
  • Updates can arrive out of order, for example after a retry. Use sequence to work out which is newest for a connection, not the order they arrive in.

Send a test

You can send a test to check your address and signature code. A test is a real, signed request sent once only. It is nbn.webhook.ping unless you choose another event, has "test": true in data, and does not count towards the failed-in-a-row totals.

Options and limits

Webhooks per account
Up to 10.
Custom headers
Up to 5 per webhook, for example an API key your server expects. Values are stored encrypted and hidden in the delivery log. Names starting with X-Crazytel-, and standard ones like Host, Content-Type and User-Agent, cannot be used.
Layouts
JSON, Slack, Microsoft Teams, Discord or Google Chat.
Old updates
An update that could not be started within 24 hours (for example while the webhook was paused) is cancelled rather than sent late.
Cost
There is no charge for NBN® webhooks.

If deliveries fail

Open the Delivery log tab and select the update. Each try shows the reply we got from your server and a plain explanation:

MessageWhat to check
We could not find your serverThe host name in the address is spelled correctly and has a public DNS record.
We could not make a secure connectionYour certificate is valid, not expired, and matches the host name.
No answer in time / did not reply in timeYour server is online, and replies within 10 seconds.
Your server refused the connectionYour server is running, and your firewall lets in 103.140.134.210 and 103.137.56.120.
Your server did not accept the requestA 4xx reply. Often a signature check or a missing custom header.
Your server asked us to slow downA 429 reply. We try again later.
Your server had an errorA 5xx reply. Check your server's logs.
Private or blocked network addressThe address points to a private network. Use a public address.
Your server sent a redirectUse the final address, including the right https:// and path.

Still stuck? Call us on 1800 272 998 or raise a ticket in the portal helpdesk, and quote the X-Crazytel-Delivery id from the log.

Need a hand configuring this setup?Our Australian engineering team can verify your trunk, PBX, or routing configuration.
Contact Support
Need Help?