Skip to content

Webhooks

Get notified in real time when users cross spending thresholds, hit gates, or on a schedule — via HTTP POST to your endpoint.

Paygent can POST event data to a URL you configure whenever something meaningful happens. Use webhooks to trigger Slack alerts, send upgrade emails, reconcile billing, or feed your own alerting system — without polling.

Event types

Event type Trigger What it means
gate_event.soft_gate User hit a soft gate Warning threshold (default 80%) crossed
gate_event.hard_gate User hit a hard gate Limit reached, call was checked
gate_event.blocked Call was blocked Hard gate fired, no tokens consumed
usage.threshold.50 User crossed 50% of plan spend limit Halfway through their budget
usage.threshold.80 User crossed 80% of plan spend limit Approaching limit
usage.threshold.100 User crossed 100% of plan spend limit Over limit
usage.summary.daily Scheduled (6 AM UTC daily) Daily usage rollup for your product
usage.summary.weekly Scheduled (Monday 6 AM UTC) Weekly usage rollup
usage.summary.monthly Scheduled (1st of month 6 AM UTC) Monthly usage rollup

Threshold events (usage.threshold.*) fire once per user per billing period — you won't get spammed if a user hovers around the 80% mark.

Create a webhook endpoint

Via API

curl -X POST https://api.paygent.to/api/v1/webhooks/endpoints \
  -H "Authorization: Bearer pg_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/paygent",
    "subscribed_events": ["gate_event.hard_gate", "usage.threshold.80", "usage.threshold.100"],
    "description": "Production alerting"
  }'

Response (201):

{
  "id": "550e8400-...",
  "url": "https://your-app.com/webhooks/paygent",
  "secret": "whsec_a1b2c3d4...",
  "subscribed_events": ["gate_event.hard_gate", "usage.threshold.80", "usage.threshold.100"],
  "description": "Production alerting",
  "enabled": true
}

Save the secret — it's shown only on creation. You'll use it to verify webhook signatures. If you lose it, rotate it via POST /webhooks/endpoints/{id}/rotate-secret.

Via Dashboard

  1. Go to app.paygent.toWebhooks
  2. Click Create Endpoint
  3. Enter your URL and select the event types you want
  4. Copy the signing secret

Payload format

Every webhook POST has this envelope:

{
  "id": "whevt_550e8400-...",
  "type": "gate_event.hard_gate",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T14:30:00Z",
  "product_id": "...",
  "data": { ... }
}

Headers

Content-Type: application/json
User-Agent: Paygent-Webhooks/1.0
X-Paygent-Event: gate_event.hard_gate
X-Paygent-Delivery: whevt_550e8400-...
X-Paygent-Signature: sha256=<hex>
X-Paygent-Timestamp: 1719063000

Verifying signatures

Paygent signs every webhook with HMAC-SHA256. Verify it to ensure the request came from Paygent:

import hmac
import hashlib

def verify_signature(payload_body: bytes, signature_header: str, timestamp_header: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        f"{timestamp_header}.{payload_body.decode()}".encode(),
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature_header)

Gate event payload (gate_event.*)

{
  "data": {
    "user_id": "user_123",
    "status": "hard_gate",
    "gate_reason": "total_spend",
    "usage_pct": 1.05,
    "current_value": 10.50,
    "limit_value": 10.00,
    "blocked": true,
    "message": "Spend limit reached"
  }
}

Threshold payload (usage.threshold.*)

{
  "data": {
    "user_id": "user_123",
    "threshold_pct": 80,
    "current_spend": 8.05,
    "spend_limit": 10.00,
    "plan_name": "pro",
    "tokens_total": 145200,
    "cost_by_model": {"gpt-4o": 5.20, "claude-sonnet": 2.85}
  }
}

Summary payload (usage.summary.*)

{
  "data": {
    "summary_type": "daily",
    "period_start": "2026-06-21T00:00:00Z",
    "period_end": "2026-06-22T00:00:00Z",
    "active_users": 42,
    "total_cost": 127.45,
    "total_tokens": 2340000,
    "total_events": 1823,
    "soft_gates": 12,
    "hard_gates": 3,
    "top_users": [{"user_id": "user_123", "cost": 15.20, "tokens": 280000}]
  }
}

Retry behavior

If your endpoint returns a non-2xx status or times out (10s), Paygent retries with exponential backoff:

Attempt Delay
1 Immediate
2 1 minute
3 5 minutes
4 30 minutes
5 2 hours
6 8 hours

After 6 failed attempts (~10.5 hours total), the delivery is marked as failed. You can inspect failed deliveries in the dashboard or via the API.

Managing endpoints

Action API Dashboard
List endpoints GET /webhooks/endpoints Webhooks page
Update URL or events PATCH /webhooks/endpoints/{id} Edit button
Disable/enable PATCH /webhooks/endpoints/{id} with enabled: false/true Toggle
Rotate secret POST /webhooks/endpoints/{id}/rotate-secret Rotate button
View delivery log GET /webhooks/endpoints/{id}/deliveries Deliveries tab
Send test event POST /webhooks/endpoints/{id}/test Test button
Delete DELETE /webhooks/endpoints/{id} Delete button

Common patterns

Slack alert on hard gate

Subscribe to gate_event.hard_gate, parse the data.user_id and data.message, and POST a formatted message to a Slack incoming webhook.

Upgrade email on 80% threshold

Subscribe to usage.threshold.80, look up the user's email in your system, and send an email prompting them to upgrade.

Daily cost Slack digest

Subscribe to usage.summary.daily, format the top users and total cost, and post to a #cost-monitoring channel.

Billing reconciliation

Subscribe to usage.threshold.100, and when a user crosses 100%, call your billing system to charge overage or suspend access.

What's next