LedgerCore
Webhooks

Webhooks Overview

LedgerCore accepts inbound webhooks from trusted partners so that activity performed outside the REST gateway still flows into our unified history, credit system, and subscription model. All webhooks are idempotent and authenticated at the edge.

Direction

Today LedgerCore only processes inbound webhooks (third-party → gateway). Outbound subscriptions (gateway → your URL) are on the roadmap — until then, use the Realtime API for push notifications.

Registered endpoints

Common patterns

All inbound webhooks share a few conventions:

  • Endpoint convention: every webhook lives under /api/webhook/<source> on the gateway.
  • HTTP semantics: always POST with Content-Type: application/json.
  • Authentication: a shared secret header or a provider-signed payload. Unauthenticated requests return 401 immediately.
  • Idempotency: handlers de-duplicate by event.id (or equivalent) so retrying the same webhook is safe.
  • Response contract: 2xx means "accepted, stop retrying". 5xx or a timeout means the sender should retry with exponential backoff.
  • Latency budget: target under 2 s per request — webhooks run synchronously through the gateway middleware stack.

Security

Rotate your secrets

All webhook secrets live in environment variables and are validated on every request. Rotate them regularly and never commit them to source control. Compromised secrets can be revoked instantly via the admin console.

WebhookAuth mechanismEnv var
ActivityX-Activity-Webhook-Secret header (shared)ACTIVITY_WEBHOOK_SECRET
ClerkSvix-style signature via X-Clerk-Webhook-SignatureCLERK_WEBHOOK_SECRET
PayPalPayPal signature verification (PayPal SDK)PAYPAL_WEBHOOK_ID
PayFastMD5 signature over ordered paramsPAYFAST_MERCHANT_KEY

Testing locally

In development you can drive any endpoint with curl — just make sure the secret matches the one configured in your .env:

curl -X POST http://localhost:8090/api/webhook/activity \
  -H "Content-Type: application/json" \
  -H "X-Activity-Webhook-Secret: $ACTIVITY_WEBHOOK_SECRET" \
  -d '{
    "activityType": "kyt",
    "userId": "user_32T5kyEywX9x8X3P3XGxcyptIbn",
    "statusCode": 200,
    "blockchain": "bitcoin",
    "transactionHash": "abc123..."
  }'

Successful posts return:

{ "success": true, "id": "uuid-of-created-activity", "requestId": "…" }
Was this page helpful?