Skip to main content

Webhook Management

Manage your webhook endpoints programmatically via the API. Create, update, and delete endpoints without using the dashboard.
For webhook event types and payload formats, see Webhook Events.

Create a Webhook

curl -X POST https://api.ledger.so/v1/webhooks \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/ledger",
    "description": "Production webhook endpoint",
    "events": ["transaction.completed", "card.created"]
  }'
{
  "object": "webhook",
  "id": "whk_abc123",
  "url": "https://your-server.com/webhooks/ledger",
  "description": "Production webhook endpoint",
  "events": ["transaction.completed", "card.created"],
  "status": "enabled",
  "secret": "whsec_abc123...",
  "createdAt": 1703520000000
}
The secret is only returned when creating a webhook. Store it securely - you’ll need it to verify webhook signatures.

Event Filtering

FieldDescription
eventsArray of event types to receive
(empty array)Receive all events
# Receive only transaction events
curl -X POST https://api.ledger.so/v1/webhooks \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks",
    "events": [
      "transaction.authorized",
      "transaction.completed",
      "transaction.declined"
    ]
  }'

List Webhooks

curl https://api.ledger.so/v1/webhooks \
  -H "Api-Key: $API_KEY"
{
  "object": "list",
  "data": [
    {
      "object": "webhook",
      "id": "whk_abc123",
      "url": "https://your-server.com/webhooks/ledger",
      "description": "Production endpoint",
      "events": ["transaction.completed"],
      "status": "enabled",
      "createdAt": 1703520000000
    }
  ],
  "hasMore": false
}

Get Webhook

curl https://api.ledger.so/v1/webhooks/whk_abc123 \
  -H "Api-Key: $API_KEY"

Update Webhook

curl -X PATCH https://api.ledger.so/v1/webhooks/whk_abc123 \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://new-server.com/webhooks",
    "events": ["transaction.completed", "transaction.declined"],
    "status": "enabled"
  }'

Disable/Enable

# Disable
curl -X PATCH https://api.ledger.so/v1/webhooks/whk_abc123 \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "disabled"}'

# Enable
curl -X PATCH https://api.ledger.so/v1/webhooks/whk_abc123 \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "enabled"}'

Delete Webhook

curl -X DELETE https://api.ledger.so/v1/webhooks/whk_abc123 \
  -H "Api-Key: $API_KEY"
{
  "object": "deleted",
  "id": "whk_abc123",
  "deleted": true
}

Signing Secret

Get Secret

Retrieve the signing secret for an existing webhook:
curl https://api.ledger.so/v1/webhooks/whk_abc123/secret \
  -H "Api-Key: $API_KEY"
{
  "object": "webhook_secret",
  "secret": "whsec_abc123..."
}

Rotate Secret

Generate a new signing secret:
curl -X POST https://api.ledger.so/v1/webhooks/whk_abc123/rotate-secret \
  -H "Api-Key: $API_KEY"
{
  "object": "webhook_secret",
  "secret": "whsec_new456..."
}
After rotating, you have 24 hours to update your server. Both old and new secrets work during this grace period.

Test Webhook

Send a test event to verify your endpoint is working:
curl -X POST https://api.ledger.so/v1/webhooks/whk_abc123/test \
  -H "Api-Key: $API_KEY"
{
  "object": "test_sent",
  "success": true,
  "message": "Test webhook sent",
  "payload": {
    "id": "test_1703520000",
    "type": "test.webhook",
    "createdAt": 1703520000000,
    "data": {
      "message": "This is a test webhook event from Ledger API"
    }
  }
}

List Event Types

Get all available webhook event types:
curl https://api.ledger.so/v1/webhook-event-types \
  -H "Api-Key: $API_KEY"
{
  "object": "list",
  "data": [
    {"name": "transaction.authorized", "category": "transaction"},
    {"name": "transaction.completed", "category": "transaction"},
    {"name": "card.created", "category": "card"},
    {"name": "card.frozen", "category": "card"},
    {"name": "agent.created", "category": "agent"}
  ]
}

Verifying Webhooks

All webhook payloads are signed using Svix. Verify the signature using the svix library: Headers:
  • svix-id - Unique message ID
  • svix-timestamp - Unix timestamp
  • svix-signature - HMAC signature
const { Webhook } = require('svix');

const webhook = new Webhook(process.env.WEBHOOK_SECRET);

// In your webhook handler
app.post('/webhooks', (req, res) => {
  try {
    const payload = webhook.verify(req.body, {
      'svix-id': req.headers['svix-id'],
      'svix-timestamp': req.headers['svix-timestamp'],
      'svix-signature': req.headers['svix-signature']
    });

    // Process the webhook
    console.log(`Received ${payload.type}:`, payload.data);

    res.status(200).send('OK');
  } catch (err) {
    console.error('Webhook verification failed:', err);
    res.status(400).send('Invalid signature');
  }
});
Install the svix library: npm install svix or pip install svix

Webhook Events

See all event types and payload formats