Webhooks

Configure webhooks to receive real-time notifications when events occur in your Logproof account. Webhooks are HTTP callbacks that Logproof will POST to your specified URL.

Webhook Payload Format

All webhook deliveries use the following JSON structure:

{
  "id": "wh_evt_1a2b3c4d5e6f",
  "event": "event.created",
  "data": {
    // Event-specific data
  },
  "timestamp": "2026-02-10T14:30:00Z"
}

Signature Verification

Each webhook request includes an X-Logproof-Signature header containing an HMAC-SHA256 signature of the request body. Use your webhook secret to verify the signature and ensure the request came from Logproof.

const crypto = require('crypto');

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

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}
function verifySignature($body, $signature, $secret) {
    $expectedSignature = hash_hmac('sha256', $body, $secret);

    return hash_equals($expectedSignature, $signature);
}
import hmac
import hashlib

def verify_signature(body, signature, secret):
    expected_signature = hmac.new(
        secret.encode(),
        body.encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected_signature, signature)

Retry Policy

If your webhook endpoint returns a non-2xx status code or times out, Logproof will retry the delivery up to 3 times with exponential backoff:

  • 1st retry: after 1 minute
  • 2nd retry: after 5 minutes
  • 3rd retry: after 15 minutes
Note: Your endpoint should respond with a 2xx status code within 10 seconds to be considered successful.

Create Webhook

POST https://logproof.de/v1/webhooks

Creates a new webhook endpoint to receive event notifications.

Required Scope: keys:manage

Request Body

Parameter Type Required Description
url string Yes The HTTPS URL to send webhook payloads to
events array Yes Array of event patterns to subscribe to (e.g., event.created, *)
active boolean No Whether the webhook is active (default: true)

Example Request

curl -X POST https://logproof.de/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/logproof",
    "events": ["event.created", "event.verified"],
    "active": true
  }'
const response = await fetch('https://logproof.de/v1/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://example.com/webhooks/logproof',
    events: ['event.created', 'event.verified'],
    active: true
  })
});

const data = await response.json();
$client = new \GuzzleHttp\Client();

$response = $client->post('https://logproof.de/v1/webhooks', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_KEY',
        'Content-Type' => 'application/json'
    ],
    'json' => [
        'url' => 'https://example.com/webhooks/logproof',
        'events' => ['event.created', 'event.verified'],
        'active' => true
    ]
]);

$data = json_decode($response->getBody(), true);
import requests

response = requests.post(
    'https://logproof.de/v1/webhooks',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'url': 'https://example.com/webhooks/logproof',
        'events': ['event.created', 'event.verified'],
        'active': True
    }
)

data = response.json()

Response (201 Created)

{
  "data": {
    "id": "wh_1a2b3c4d5e6f",
    "url": "https://example.com/webhooks/logproof",
    "events": ["event.created", "event.verified"],
    "active": true,
    "secret": "whsec_1a2b3c4d5e6f7g8h9i0j",
    "created_at": "2026-02-10T14:30:00Z"
  }
}
Important: The secret is only returned once during creation. Store it securely to verify webhook signatures. You cannot retrieve it later.

List Webhooks

GET https://logproof.de/v1/webhooks

Retrieves a list of all configured webhooks for your account.

Required Scope: keys:manage

Example Request

curl -X GET https://logproof.de/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch('https://logproof.de/v1/webhooks', {
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const data = await response.json();
$client = new \GuzzleHttp\Client();

$response = $client->get('https://logproof.de/v1/webhooks', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_KEY'
    ]
]);

$data = json_decode($response->getBody(), true);
import requests

response = requests.get(
    'https://logproof.de/v1/webhooks',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY'
    }
)

data = response.json()

Response Body

{
  "data": [
    {
      "id": "wh_1a2b3c4d5e6f",
      "url": "https://example.com/webhooks/logproof",
      "events": ["event.created", "event.verified"],
      "active": true,
      "created_at": "2026-02-10T14:30:00Z"
    },
    {
      "id": "wh_9z8y7x6w5v4u",
      "url": "https://backup.example.com/hooks",
      "events": ["*"],
      "active": false,
      "created_at": "2026-02-08T10:15:00Z"
    }
  ]
}

Update Webhook

PATCH https://logproof.de/v1/webhooks/{id}

Updates the configuration of an existing webhook.

Required Scope: keys:manage

Request Body

Parameter Type Required Description
url string No The new URL for the webhook
events array No Updated array of event patterns
active boolean No Enable or disable the webhook

Example Request

curl -X PATCH https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["*"],
    "active": false
  }'
const response = await fetch('https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    events: ['*'],
    active: false
  })
});

const data = await response.json();
$client = new \GuzzleHttp\Client();

$response = $client->patch('https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_KEY',
        'Content-Type' => 'application/json'
    ],
    'json' => [
        'events' => ['*'],
        'active' => false
    ]
]);

$data = json_decode($response->getBody(), true);
import requests

response = requests.patch(
    'https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'events': ['*'],
        'active': False
    }
)

data = response.json()

Response Body

{
  "data": {
    "id": "wh_1a2b3c4d5e6f",
    "url": "https://example.com/webhooks/logproof",
    "events": ["*"],
    "active": false,
    "created_at": "2026-02-10T14:30:00Z"
  }
}

Delete Webhook

DELETE https://logproof.de/v1/webhooks/{id}

Permanently deletes a webhook. This action cannot be undone.

Required Scope: keys:manage

Example Request

curl -X DELETE https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f \
  -H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch('https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

// Response status: 204 No Content
$client = new \GuzzleHttp\Client();

$response = $client->delete('https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_KEY'
    ]
]);

// Response status: 204 No Content
import requests

response = requests.delete(
    'https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY'
    }
)

# Response status: 204 No Content

Response

Returns 204 No Content on successful deletion.

Get Delivery History

GET https://logproof.de/v1/webhooks/{id}/deliveries

Retrieves the delivery history for a specific webhook, including success and failure information.

Required Scope: keys:manage

Example Request

curl -X GET https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f/deliveries \
  -H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch('https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f/deliveries', {
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const data = await response.json();
$client = new \GuzzleHttp\Client();

$response = $client->get('https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f/deliveries', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_KEY'
    ]
]);

$data = json_decode($response->getBody(), true);
import requests

response = requests.get(
    'https://logproof.de/v1/webhooks/wh_1a2b3c4d5e6f/deliveries',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY'
    }
)

data = response.json()

Response Body

{
  "data": [
    {
      "id": "wh_del_1a2b3c4d",
      "event": "event.created",
      "status": "success",
      "status_code": 200,
      "attempts": 1,
      "delivered_at": "2026-02-10T14:30:00Z"
    },
    {
      "id": "wh_del_5e6f7g8h",
      "event": "event.verified",
      "status": "failed",
      "status_code": 500,
      "attempts": 3,
      "last_attempt_at": "2026-02-10T14:45:00Z",
      "next_retry_at": null
    }
  ]
}