Webhooks / Event types
Webhook event types
Every event a webhook can subscribe to, grouped by resource, with what each one means and the fields billing events carry.
A webhook subscribes to exact types, to every type of one resource with <resource>.*, or to everything with *. The same list, with a one-line description of each type, comes from the API:
$ curl https://api.pantechdynamics.com/public/v1/webhook-event-types \ -H "Authorization: Bearer $PANTECH_API_KEY"Every event arrives in the same envelope, described in What is sent. Only data differs.
Infrastructure
Every change to a resource is an operation, and every operation that ends sends one event: <resource>.<past tense> when it finished, <resource>.<verb>_failed when it failed. Both kinds carry the same data:
| Field | What it is |
|---|---|
resource_type | The resource, as in the event type: instance, volume, kubernetes_cluster… |
resource_id | The resource's id (vm_…, vol_…, db_…). |
operation_id | The operation that made the change (op_…). |
action | The verb that was asked for, as in the _failed type: create, attach, resize_storage… |
status | succeeded or failed. |
error | Only when status is failed: code and message, the same as the operation's failure. |
Events are deliberately thin. To know more, such as a machine's address after instance.created, read the resource through the API with resource_id.
Instances
Subscribe to all of them with instance.*.
| Finished | Failed | What happened |
|---|---|---|
instance.created | instance.create_failed | A machine was created and is running. |
instance.started | instance.start_failed | A machine was started. |
instance.stopped | instance.stop_failed | A machine was stopped. |
instance.rebooted | instance.reboot_failed | A machine was rebooted. |
instance.renamed | instance.rename_failed | A machine was renamed. |
instance.rebuilt | instance.rebuild_failed | A machine's root disk was rebuilt from an image. |
instance.deleted | instance.delete_failed | A machine was deleted. |
instance.deletion_protection_enabled | instance.enable_deletion_protection_failed | Deletion protection was turned on. |
instance.deletion_protection_disabled | instance.disable_deletion_protection_failed | Deletion protection was turned off. |
instance.restored | instance.restore_failed | A machine was restored from one of its snapshots. |
instance.resized | instance.resize_failed | A machine was moved to another plan. |
instance.ssh_key_changed | instance.change_ssh_key_failed | A machine's SSH key was changed. |
instance.security_group_changed | instance.change_security_group_failed | A machine was moved to another security group. |
instance.private_network_attached | instance.attach_private_network_failed | A machine was given an interface on its zone's private database network. |
instance.private_network_detached | instance.detach_private_network_failed | That interface was removed. |
Volumes
Subscribe to all of them with volume.*.
| Finished | Failed | What happened |
|---|---|---|
volume.created | volume.create_failed | A volume was created. |
volume.attached | volume.attach_failed | A volume was attached to a machine. |
volume.detached | volume.detach_failed | A volume was detached. |
volume.resized | volume.resize_failed | A volume was grown. |
volume.deleted | volume.delete_failed | A volume was deleted. |
Snapshots
Subscribe to all of them with snapshot.*.
| Finished | Failed | What happened |
|---|---|---|
snapshot.created | snapshot.create_failed | A snapshot was taken, by hand or by a schedule. |
snapshot.deleted | snapshot.delete_failed | A snapshot was deleted. |
VPC networks
Subscribe to all of them with network.*.
| Finished | Failed | What happened |
|---|---|---|
network.created | network.create_failed | A VPC was created. |
network.deleted | network.delete_failed | A VPC was deleted. |
Subnets
Subscribe to all of them with subnet.*.
| Finished | Failed | What happened |
|---|---|---|
subnet.created | subnet.create_failed | A subnet was created. |
subnet.deleted | subnet.delete_failed | A subnet was deleted. |
Firewall rules
Subscribe to all of them with firewall_rule.*.
| Finished | Failed | What happened |
|---|---|---|
firewall_rule.created | firewall_rule.create_failed | A rule was added to a subnet's firewall. |
firewall_rule.deleted | firewall_rule.delete_failed | A rule was removed. |
Security groups
Subscribe to all of them with security_group.*.
| Finished | Failed | What happened |
|---|---|---|
security_group.created | security_group.create_failed | A security group was created. |
security_group.rules_updated | security_group.update_rules_failed | A security group's rules were changed. |
security_group.deleted | security_group.delete_failed | A security group was deleted. |
Public IPs
Subscribe to all of them with public_ip.*.
| Finished | Failed | What happened |
|---|---|---|
public_ip.created | public_ip.create_failed | A public IP was reserved. |
public_ip.deleted | public_ip.delete_failed | A public IP was released. |
public_ip.attached | public_ip.attach_failed | A public IP was attached to a machine. |
public_ip.detached | public_ip.detach_failed | A public IP was taken off its machine. |
Port forwarding rules
Subscribe to all of them with port_forwarding_rule.*.
| Finished | Failed | What happened |
|---|---|---|
port_forwarding_rule.created | port_forwarding_rule.create_failed | A port forward was added to a public IP. |
port_forwarding_rule.deleted | port_forwarding_rule.delete_failed | A port forward was removed. |
Load balancers
Subscribe to all of them with load_balancer.*.
| Finished | Failed | What happened |
|---|---|---|
load_balancer.created | load_balancer.create_failed | A load balancer was created. |
load_balancer.updated | load_balancer.update_failed | A load balancer's name, algorithm or targets were changed. |
load_balancer.deleted | load_balancer.delete_failed | A load balancer was deleted. |
Databases
Subscribe to all of them with database.*.
| Finished | Failed | What happened |
|---|---|---|
database.created | database.create_failed | A database was created and is running. |
database.started | database.start_failed | A database was started. |
database.stopped | database.stop_failed | A database was stopped. |
database.deleted | database.delete_failed | A database was deleted. |
database.access_rules_updated | database.update_access_rules_failed | The CIDRs allowed to connect were changed. |
database.password_changed | database.change_password_failed | The admin password was changed to one you chose. |
database.password_reset | database.reset_password_failed | The admin password was reset to a generated one. |
database.storage_resized | database.resize_storage_failed | The data disk was grown. |
Kubernetes clusters
Subscribe to all of them with kubernetes_cluster.*.
| Finished | Failed | What happened |
|---|---|---|
kubernetes_cluster.created | kubernetes_cluster.create_failed | A cluster was created and is running. |
kubernetes_cluster.scaled | kubernetes_cluster.scale_failed | The number of workers was changed. |
kubernetes_cluster.upgraded | kubernetes_cluster.upgrade_failed | A cluster was upgraded to a newer Kubernetes version. |
kubernetes_cluster.started | kubernetes_cluster.start_failed | A cluster was started. |
kubernetes_cluster.stopped | kubernetes_cluster.stop_failed | A cluster was stopped. |
kubernetes_cluster.deleted | kubernetes_cluster.delete_failed | A cluster was deleted. |
kubernetes_cluster.configured | kubernetes_cluster.configure_failed | A cluster's settings were changed. |
kubernetes_cluster.nodes_resized | kubernetes_cluster.resize_nodes_failed | The nodes were moved to another plan. |
kubernetes_cluster.network_upgraded | kubernetes_cluster.upgrade_network_failed | The cluster's pod network was upgraded. |
Billing
Amounts are integers in minor units of currency (kobo for NGN, cents for USD): amount_minor: 1504000 in NGN is NGN 15,040.00. Times are RFC 3339, UTC. Subscribe to every event of one kind with its prefix, such as invoice.* or credit.*. See how billing works.
| Event | When | data |
|---|---|---|
invoice.issued | A billing period closed and its invoice was issued. | invoice_id, invoice_number, currency, subtotal_minor, tax_minor, tax_rate_bps (VAT in basis points: 750 is 7.5%), total_minor, credit_applied_minor, brought_forward_minor, total_due_minor |
invoice.paid | An invoice was paid, by card or from credit. | invoice_id, invoice_number, currency, amount_minor, paid_with (payment or credit), receipt_id when paid by card |
payment.received | A payment was received. | receipt_id, purpose (such as invoice_collection, credit_purchase, verification or initial_payment), currency, amount_minor |
payment.failed | Collecting an invoice failed; another attempt is scheduled. | currency, amount_due_minor, attempt_number, next_retry_at (left out when no automatic retry remains), past_due_on |
credit.low | Credit no longer covers the estimated next invoice. | currency, available_minor, prepaid_minor, projected_invoice_minor, next_invoice_at, has_payment_method |
credit.depleted | Credit has run out. | The same fields as credit.low |
credit_purchase.succeeded | A credit purchase was paid and added to the balance. | currency, amount_minor, new_balance_minor and receipt_id when known |
credit_purchase.failed | A credit purchase failed. | currency, amount_minor |
receipt.issued | A receipt was issued. | receipt_number, kind (payment, invoice_payment, credit_purchase, wallet_debit or refund), currency, amount_minor |
account.activated | The account's verification payment succeeded and it can create resources. | Empty |
account.past_due | The account is past due. | reason_code, currency, amount_owed_minor |
account.current | The account is no longer past due. | Empty |
spend_cap.reached | Unbilled usage reached the account's spend cap. | currency, accrued_minor, cap_minor |
{
"id": "evt_06gk3x9tq7m2v8r4y1c5d0zp8w",
"type": "invoice.paid",
"api_version": "2026-10-22",
"created_at": "2026-11-01T00:12:40Z",
"organization_id": "org_06gk3x9tq7m2v8r4y1c5d0zp8w",
"project_id": "acc_06gk3x9tq7m2v8r4y1c5d0zp8w",
"data": {
"invoice_id": "inv_06gk3x9tq7m2v8r4y1c5d0zp8w",
"invoice_number": "INV-d0zp8w-0007",
"currency": "NGN",
"amount_minor": 1504000,
"paid_with": "payment",
"receipt_id": "rct_06gk3x9tq7m2v8r4y1c5d0zp8w"
}
}Test
| Event | When | data |
|---|---|---|
webhook.test | You asked for a test event. It is sent whatever the webhook subscribes to, and you cannot subscribe to it. | endpoint_id (the webhook's id), message |
New event types
New types are added from time to time, and a <resource>.* or * subscription receives them without a change. Ignore a type you do not recognise and answer 2xx anyway, or it is retried. A new field in data is not a breaking change either: ignore fields you do not use. A change that would break a receiver comes with a new api_version.