Billing Webhooks

Receive webhook notifications for SALZ billing events -- usage thresholds, plan changes, and payment status updates.

SALZ can send webhook notifications to your application when billing events occur. This lets you react to usage changes, plan upgrades, and payment issues without polling the API.

Available Events

EventDescription
usage.threshold.80Account has used 80% of monthly quota
usage.threshold.100Account has reached 100% of monthly quota
plan.upgradedAccount upgraded to a higher tier
plan.downgradedAccount downgraded to a lower tier
payment.succeededMonthly payment was processed successfully
payment.failedPayment attempt failed

Setting Up Webhooks

Billing webhooks are available on the Pro and Enterprise plans.

  1. Go to your SALZ dashboard.
  2. Navigate to Settings > Webhooks.
  3. Enter your webhook endpoint URL (must be HTTPS).
  4. Select the events you want to receive.
  5. Save your configuration.

SALZ will send a test event to verify your endpoint is reachable.

Webhook Payload

All webhook events follow the same JSON structure:

{
  "event": "usage.threshold.80",
  "timestamp": "2025-03-15T14:30:00Z",
  "data": {
    "account_id": "acc_abc123",
    "current_usage": 4000,
    "monthly_limit": 5000,
    "plan": "pro",
    "billing_period_end": "2025-04-14T00:00:00Z"
  }
}

Handling Webhooks

Your endpoint should return a 200 status code within 10 seconds to acknowledge receipt. If SALZ does not receive a 200, it will retry the webhook up to 3 times with exponential backoff (1 minute, 5 minutes, 30 minutes).

Example: Node.js / Express

app.post('/webhooks/salz', express.json(), (req, res) => {
  const { event, data } = req.body;

  switch (event) {
    case 'usage.threshold.80':
      console.log(`Account ${data.account_id} at 80% usage`);
      // Send internal alert or notify your users
      break;

    case 'usage.threshold.100':
      console.log(`Account ${data.account_id} hit quota limit`);
      // Prompt user to upgrade
      break;

    case 'payment.failed':
      console.log(`Payment failed for ${data.account_id}`);
      // Notify your billing team
      break;
  }

  res.status(200).json({ received: true });
});

Example: Next.js API Route

export async function POST(request) {
  const body = await request.json();
  const { event, data } = body;

  if (event === 'usage.threshold.100') {
    // Handle quota exhaustion
    await notifyAdmin(data.account_id);
  }

  return Response.json({ received: true });
}

Verifying Webhooks

Each webhook request includes a X-Salz-Signature header containing an HMAC-SHA256 signature of the request body. Verify this signature to confirm the webhook came from SALZ and was not tampered with.

import crypto from 'crypto';

function verifyWebhookSignature(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Your webhook signing secret is available in Settings > Webhooks in the dashboard.

Best Practices

  • Always verify signatures. Do not trust incoming webhooks without checking the HMAC signature.
  • Respond quickly. Return 200 before doing heavy processing. Queue the event for async handling if needed.
  • Handle duplicates. Retries can cause duplicate deliveries. Use the event timestamp and account ID to deduplicate.
  • Use HTTPS. Webhook endpoints must use HTTPS to protect the payload in transit.
  • Log everything. Store raw webhook payloads for debugging and audit purposes.