title: Webhooks

description: Receive real-time event notifications via webhooks.

Webhooks

Webhooks let Wontopos push events to your server in real time — subscriptions, usage alerts, billing, and more.


Create a webhook endpoint

Register a URL to receive webhook events.

POST /v1/webhooks
ParameterTypeRequiredDescription
urlstringYesHTTPS URL to receive events.
eventsstring[]YesList of event types to subscribe to.
descriptionstringNoHuman-readable label for this endpoint.
secretstringNoCustom signing secret. Auto-generated if omitted.
curl https://api.wontopos.com/v1/webhooks 
  -X POST 
  -H "Authorization: Bearer sk_live_your_key_here" 
  -H "Content-Type: application/json" 
  -d '{
    "url": "https://yourapp.com/webhooks",
    "events": ["subscription.created", "usage.limit_reached"],
    "description": "Production webhook"
  }'

Response:

{
  "id": "wh_abc123",
  "url": "https://yourapp.com/webhooks",
  "events": ["subscription.created", "usage.limit_reached"],
  "secret": "whsec_...",
  "status": "active",
  "created_at": "2026-03-30T10:00:00Z"
}

Save the secret

The webhook secret is only returned at creation time. Store it securely for signature verification.

Event types

EventDescription
subscription.createdA new subscription was created
subscription.updatedA subscription was modified (plan change, etc.)
subscription.cancelledA subscription was cancelled
usage.limit_reachedUsage has reached 80% of plan limit
usage.limit_exceededUsage has exceeded plan limit
invoice.createdA new invoice was generated
invoice.paidAn invoice was successfully paid
invoice.failedA payment attempt failed
api.updatedA subscribed API published a new version

Payload structure

All webhook payloads follow the same envelope format:

{
  "id": "evt_abc123",
  "type": "subscription.created",
  "api_version": "v1",
  "created": 1711785600,
  "data": {
    "object": {
      "id": "sub_9x8y7z",
      "api_id": "api_1a2b3c4d",
      "plan_id": "plan_pro",
      "status": "active"
    }
  }
}
FieldTypeDescription
idstringUnique event ID (use for idempotency)
typestringEvent type
api_versionstringAPI version that generated the event
createdintegerUnix timestamp
data.objectobjectThe resource that triggered the event

Signature verification

Every webhook request includes a Wontopos-Signature header. Always verify it to prevent spoofed events.

The signature is an HMAC-SHA256 hex digest of the raw request body, using your webhook secret as the key.

// Node.js
const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}
# Python
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
// Go
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func verifyWebhook(payload []byte, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(payload)
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}

Always verify signatures

Never process webhook events without verifying the signature. Failing to do so makes your application vulnerable to spoofing and replay attacks.

Retry policy

If your endpoint returns a non-2xx status code or does not respond within 30 seconds, Wontopos retries with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry24 hours

After 5 failed retries, the event is marked as failed. You can manually retry failed events from the dashboard.

Idempotency

Use the `id` field in the event payload to deduplicate. The same event may be delivered more than once.