Lær hvordan du sender data fra dine egne systemer til CaapBoard widgets via signerede HTTP requests.
Webhook-systemet gør det muligt at pushe data fra eksterne kilder til dit CaapBoard dashboard. Dette er ideelt til at vise real-time data fra dine egne servere, IoT-enheder, scripts eller tredjepartssystemer.
Gå til Webhooks-siden og klik på "Ny Webhook". Giv den et beskrivende navn (f.eks. "Raspberry Pi Sensor" eller "Salgsdata").
Vigtigt: Gem din secret key med det samme! Den vises kun én gang ved oprettelse.
Du modtager tre vigtige værdier:
https://din-app.dk/webhook/ingest550e8400-e29b-41d4-a716-446655440000a1b2c3d4e5f6...Test med curl (se næste sektion for fuld signering):
# Generér signatur og send request
SECRET="din-secret-key"
BODY='{"event":"test","idempotency_key":"test-1","timestamp":"2024-01-15T10:30:00Z","data":{}}'
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
curl -X POST https://din-app.dk/webhook/ingest \
-H "Content-Type: application/json" \
-H "X-Webhook-Id: din-webhook-id" \
-H "X-Webhook-Signature: sha256=$SIGNATURE" \
-d "$BODY"Alle requests skal signeres med HMAC-SHA256 for at bevise, at de kommer fra dig. Dette forhindrer uautoriserede requests og sikrer dataintegritet.
// 1. Opret payload som JSON string (præcis som den sendes)
payload = '{"event":"sensor.update","idempotency_key":"...",...}'
// 2. Beregn HMAC-SHA256 signatur
signature = HMAC_SHA256(secret_key, payload)
// 3. Konverter til hex string med prefix
header_value = "sha256=" + hex_encode(signature)
// 4. Send request med headers
POST /webhook/ingest
X-Webhook-Id: <din-webhook-id>
X-Webhook-Signature: sha256=<beregnet-signatur>
Content-Type: application/json
<payload>| Header | Påkrævet | Beskrivelse |
|---|---|---|
| X-Webhook-Id | Ja | Dit webhook endpoint ID (UUID) |
| X-Webhook-Signature | Ja | HMAC-SHA256 signatur med sha256= prefix |
| Content-Type | Ja | Skal være application/json |
{
"event": "sensor.temperature", // Påkrævet: Event type
"idempotency_key": "temp-2024-001", // Påkrævet: Unik nøgle
"timestamp": "2024-01-15T10:30:00Z", // Påkrævet: ISO 8601
"data": { // Valgfri: Din data
"value": 22.5,
"unit": "celsius",
"sensor_id": "living-room"
}
}sensor.update,sales.new,status.change2024-01-15T10:30:00Zimport hmac
import hashlib
import json
import requests
from datetime import datetime
import uuid
def send_webhook(url: str, webhook_id: str, secret_key: str,
event: str, data: dict) -> dict:
"""
Send signeret webhook til CaapBoard.
Args:
url: Webhook ingest URL
webhook_id: Dit webhook endpoint ID
secret_key: Din hemmelige nøgle
event: Event type (f.eks. "sensor.temperature")
data: Din payload data
"""
payload = {
"event": event,
"idempotency_key": str(uuid.uuid4()),
"timestamp": datetime.utcnow().isoformat() + "Z",
"data": data
}
# Konverter til bytes
body = json.dumps(payload, separators=(',', ':')).encode('utf-8')
# Beregn signatur
signature = hmac.new(
secret_key.encode('utf-8'),
body,
hashlib.sha256
).hexdigest()
# Send request
response = requests.post(
url,
data=body,
headers={
'Content-Type': 'application/json',
'X-Webhook-Id': webhook_id,
'X-Webhook-Signature': f'sha256={signature}'
}
)
return response.json()
# Eksempel: Send temperaturmåling
result = send_webhook(
url="https://din-app.dk/webhook/ingest",
webhook_id="din-webhook-id",
secret_key="din-secret-key",
event="sensor.temperature",
data={
"value": 22.5,
"unit": "celsius",
"location": "stue"
}
)
print(result) # {"received": true, "id": "evt_xxx"}import crypto from 'crypto';
interface WebhookPayload {
event: string;
idempotency_key: string;
timestamp: string;
data: Record<string, unknown>;
}
async function sendWebhook(
url: string,
webhookId: string,
secretKey: string,
event: string,
data: Record<string, unknown>
): Promise<{ received: boolean; id: string }> {
const payload: WebhookPayload = {
event,
idempotency_key: crypto.randomUUID(),
timestamp: new Date().toISOString(),
data
};
const body = JSON.stringify(payload);
// Beregn HMAC-SHA256 signatur
const signature = crypto
.createHmac('sha256', secretKey)
.update(body)
.digest('hex');
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Id': webhookId,
'X-Webhook-Signature': `sha256=${signature}`
},
body
});
return response.json();
}
// Eksempel: Send salgsdata
const result = await sendWebhook(
'https://din-app.dk/webhook/ingest',
'din-webhook-id',
process.env.WEBHOOK_SECRET!,
'sales.new',
{
amount: 299.00,
currency: 'DKK',
product: 'Premium Abonnement'
}
);
console.log(result);#!/bin/bash
# Konfiguration
WEBHOOK_URL="https://din-app.dk/webhook/ingest"
WEBHOOK_ID="din-webhook-id"
SECRET_KEY="din-secret-key"
# Funktion til at sende webhook
send_webhook() {
local event="$1"
local data="$2"
# Opret payload
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
local idempotency_key=$(uuidgen)
local body=$(cat <<EOF
{"event":"$event","idempotency_key":"$idempotency_key","timestamp":"$timestamp","data":$data}
EOF
)
# Beregn signatur
local signature=$(echo -n "$body" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)
# Send request
curl -s -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-Webhook-Id: $WEBHOOK_ID" \
-H "X-Webhook-Signature: sha256=$signature" \
-d "$body"
}
# Eksempel: Send systemstatus
send_webhook "system.status" '{"cpu":45,"memory":62,"disk":78}'<?php
function sendWebhook(
string $url,
string $webhookId,
string $secretKey,
string $event,
array $data
): array {
$payload = json_encode([
'event' => $event,
'idempotency_key' => uniqid('', true),
'timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
'data' => $data
], JSON_UNESCAPED_SLASHES);
$signature = hash_hmac('sha256', $payload, $secretKey);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"X-Webhook-Id: $webhookId",
"X-Webhook-Signature: sha256=$signature"
]
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// Eksempel: Send lageroptælling
$result = sendWebhook(
'https://din-app.dk/webhook/ingest',
'din-webhook-id',
$_ENV['WEBHOOK_SECRET'],
'inventory.update',
['sku' => 'PROD-001', 'quantity' => 42]
);
var_dump($result);| Status | Fejlkode | Beskrivelse | Handling |
|---|---|---|---|
| 200 | - | Event modtaget succesfuldt | Ingen handling nødvendig |
| 200 | duplicate: true | Idempotency key allerede set | Sikker at ignorere (idempotent) |
| 400 | invalid_json | Request body er ikke gyldig JSON | Tjek JSON-formatering |
| 400 | missing_field | Påkrævet felt mangler | Tilføj manglende felt (se "field") |
| 400 | invalid_timestamp | Timestamp er ikke valid ISO 8601 | Brug format: YYYY-MM-DDTHH:mm:ssZ |
| 401 | unknown_endpoint | Webhook ID ikke fundet | Tjek X-Webhook-Id header |
| 401 | invalid_signature | Signatur matcher ikke | Tjek secret key og signeringslogik |
| 429 | rate_limited | For mange requests | Vent "retry_after" sekunder |
Implementer exponential backoff: vent 1s → 2s → 4s → 8s mellem retry-forsøg. Respektér altid Retry-After header ved 429 responses.
Raspberry Pi eller Arduino sender temperatur, luftfugtighed og andre målinger til dit dashboard.
{"event":"sensor.reading","data":{"temp":22.5,"humidity":45}}Send realtids salgstal, ordrer eller KPI'er fra dit ERP eller regnskabssystem.
{"event":"sales.daily","data":{"revenue":45000,"orders":127}}Cron job der sender CPU, RAM og disk-forbrug hver 5. minut.
{"event":"server.metrics","data":{"cpu":45,"memory":62,"disk":78}}Modtag beskeder fra andre systemer – CI/CD builds, GitHub webhooks, eller custom alerts.
{"event":"build.completed","data":{"status":"success","branch":"main"}}Opret din første webhook og begynd at sende data til dit dashboard.
Opret Webhook