Skip to main content

Webhooks

Webhooks let you receive real-time payment.succeeded notifications whenever a buyer pays for any of your resources โ€” endpoints, products, components, or agent endpoints.
Plan Requirement: Webhooks are available on Pro and Business plans only. Free plan accounts receive a 403 response.

How It Works

Webhooks are account-level (seller-level), not per-resource. You register one webhook URL and it receives events for all resources you own.
  1. ๐Ÿ’ฐ Payment Happens โ€” Buyer pays for any of your resources
  2. ๐Ÿ“ก Webhook Fires โ€” Signed POST request to your URL
  3. โœ… You Act โ€” Fulfill order, grant access, log it

Setup via Dashboard

  1. Go to Dashboard โ†’ Webhooks
  2. Click Create Webhook
  3. Enter your HTTPS endpoint URL
  4. A signing secret is generated automatically โ€” copy and store it securely
From the Webhooks dashboard you can also toggle webhooks on/off, rotate the signing secret, delete webhooks, and view recent delivery logs.

Event: payment.succeeded

Every webhook delivery is a POST request with this JSON body:
{
  "id": "evt_abc123",
  "event": "payment.succeeded",
  "timestamp": "2026-02-26T19:30:00Z",
  "data": {
    "source": "endpoint",
    "source_id": "ep_xyz789",
    "source_slug": "my-api",
    "amount": "1.00",
    "currency": "USDC",
    "tx_hash": "0xabc...def",
    "payer_wallet": "0x1234...5678",
    "network": "base",
    "status": "settled"
  }
}
FieldDescription
sourceResource type: endpoint, product
source_slugThe slug of the resource that was paid for
amount / currencyPayment amount and asset (e.g. USDC)
tx_hashOn-chain transaction hash
networkbase or solana

Verifying Signatures

Studio seller webhooks are HMAC-signed. Current deliveries include:
  • X-X402-Signature โ€” HMAC-SHA256 hex digest
  • X-X402-Timestamp โ€” Unix timestamp for the delivery
  • X-X402-Event โ€” event type for routing/logging
  • X-X402-Event-Id โ€” stable event id for idempotency/replay protection
Verify:
  • payload: timestamp.rawBody
  • algorithm: HMAC-SHA256
  • secret: webhook signing_secret
Use the raw request body bytes. Do not parse and re-serialize JSON before hashing.

Node.js

const crypto = require('crypto');

function verifyWebhook(rawBody, signature, timestamp, secret) {
  const payload = `${timestamp}.${rawBody}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Python

import hmac, hashlib

def verify_webhook(raw_body: bytes, signature: str, timestamp: str, secret: str) -> bool:
    payload = timestamp.encode() + b"." + raw_body
    expected = hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Backward Compatibility

Some older receivers still accept raw-secret headers like:
  • x-x402layer-secret
  • x-x402-secret
  • Authorization: Bearer <secret>
Keep that only as fallback for legacy clients. Current Studio deliveries should be verified with the signed HMAC headers first.

Two Secret Hops

1) Studio โ†’ your webhook receiver

  • secret: webhook signing_secret
  • auth model: HMAC verification using the signed headers above

2) Your receiver โ†’ your app settlement route

  • secret: your own app-internal shared secret
  • example: a worker sends x-x402-secret and the app verifies it with X402_WEBHOOK_SECRET
Do not confuse the Studio webhook signing secret with the app settlement secret. They solve different trust boundaries.

Coverage Matrix

SourceRouteStatus
Endpoint payments/e/:slugโœ… Live
Product payments/p/:slugโœ… Live
Components (via endpoints)โ€”โœ… Live
Agent endpoint create/agent/endpointsโœ… Live
Agent endpoint top-up/agent/endpointsโœ… Live

Best Practices

  • ๐Ÿ” Always verify signed headers first โ€” Never trust unverified payloads.
  • โšก Respond quickly (< 5s) โ€” Process asynchronously and return 200 immediately. Queue heavy work.
  • ๐Ÿ”„ Handle duplicates โ€” Use the event id for idempotency.
  • ๐Ÿ”‘ Rotate secrets carefully โ€” If deliveries suddenly start returning 401, first check whether the webhook signing secret rotated or drifted. Update the receiver before discarding the old value.
  • ๐Ÿงพ Log headers, not secrets โ€” Log signature/timestamp/event/event-id presence for debugging, but never log the secret itself.
  • ๐Ÿ› ๏ธ Know the common failure mode โ€” If Studio deliveries 401 but a manual POST with the stored secret works, the receiver likely only supports legacy raw-secret auth while Studio is sending signed webhooks.

Webhook API Reference

MethodEndpointDescription
GET/api/webhooksList your webhooks
POST/api/webhooksCreate a new webhook
PATCH/api/webhooks/:idToggle active / rotate secret
DELETE/api/webhooks/:idDelete a webhook