CloudSignLab

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/organizationThe organization of the key.
GET /api/v1/risksRisk register: likelihood, impact, residual values, treatment, status.
GET /api/v1/controlsControls with framework references and status.
GET /api/v1/incidentsIncidents with severity, status and the NIS2 flag.
GET /api/v1/suppliersSupplier register without contact details.
GET /api/v1/policiesPublished 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.created
  • risk.created
  • policy.published
  • finding.created
  • task.created
  • supplier_check.answered
  • supplier_check.decided
  • check.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.