Developers
API and webhooks
Connect CloudSignLab to your reporting and ticket tools. The API reads an organization's registers; webhooks tell your systems when something happens. Both are part of the Integrations module (Professional and above).
Authentication
Owners and admins create API keys in Organization → Integrations. Send the key in the Authorization header. Keys only read, belong to one organization and can be revoked at any time.
curl https://cloudsignlab.com/api/v1/risks?page=1&perPage=50 \
-H "Authorization: Bearer csl_…"{
"data": [{ "id": "…", "number": 7, "title": "Ransomware on file server",
"likelihood": 3, "impact": 5, "status": "open", … }],
"total": 42, "page": 1, "perPage": 50
}Lists are paged (perPage up to 100). Each key may make 300 requests in 10 minutes; above that the API answers 429. When the organization's security rules list allowed networks, keys work only from those addresses (other addresses get 403).
Endpoints
| GET /api/v1/organization | The organization of the key. |
| GET /api/v1/risks | Risk register: likelihood, impact, residual values, treatment, status. |
| GET /api/v1/controls | Controls with framework references and status. |
| GET /api/v1/incidents | Incidents with severity, status and the NIS2 flag. |
| GET /api/v1/suppliers | Supplier register without contact details. |
| GET /api/v1/policies | Published policies with version. |
Webhooks
A webhook receives a JSON POST for the events it subscribes to. The body contains identifiers and a link, no personal data; read details through the API.
incident.createdrisk.createdpolicy.publishedfinding.createdtask.createdsupplier_check.answeredsupplier_check.decidedcheck.failed
{
"id": "5f0c…",
"event": "incident.created",
"occurredAt": "2026-10-01T08:15:00.000Z",
"organization": { "id": "…", "name": "Example GmbH" },
"target": { "id": "…", "url": "https://cloudsignlab.com/dashboard/…" }
}Every request carries X-CloudSignLab-Timestamp and X-CloudSignLab-Signature (HMAC-SHA256 of "timestamp.body" with the signing secret). Reject requests older than 5 minutes or with a wrong signature:
import { createHmac, timingSafeEqual } from "node:crypto";
const verify = (secret, timestamp, body, signature) => {
const expected = "sha256=" +
createHmac("sha256", secret).update(`${timestamp}.${body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
return fresh && expected.length === signature.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
};Slack and Microsoft Teams channels get a short message with a link instead. After 20 failed deliveries in a row an integration stops until it is switched on again.