Skip to main content

The integrations API

Integrations give other systems an endpoint to call, and the desk a connection to call them.

Calling an endpoint​

POST /api/v1/in/ie_Zq2xL9…
Authorization: Bearer iks_…
Content-Type: application/json

{ "title": "Disk almost full on files-01", "severity": "major", "host": "files-01", "id": "alert-81" }
  • The body is JSON, up to 256 KB.
  • The call is checked, logged and answered right away. It is handled on the queue a moment later.
AnswerWhen
202 { "id": "…" }Accepted. The id is the call in the log.
200 { "id": "…", "duplicate": true }The same duplicate key (or Idempotency-Key header) was seen within 24 hours. The id is the earlier call.
200 { "id": "…", "captured": true }The endpoint was capturing its next call as a sample.
400 invalid_jsonThe body isn't JSON.
401 unauthorizedThe secret, or the signature, is wrong or missing.
403 ip_not_allowedThe caller's address isn't on the endpoint's IP allowlist.
404 not_foundNo such endpoint, or the endpoint or its integration is turned off.
429 rate_limitedMore calls in a minute than the endpoint allows (120 by default), or more than 600 a minute from one address.

Refused calls are logged without their body.

Signing in​

The endpoint's How the caller signs in decides which of these it expects:

  • Bearer: Authorization: Bearer <secret>.
  • Basic: Authorization: Basic base64(<anything>:<secret>). The user name is ignored.
  • Signed body (HMAC): two headers, the same as the desk's webhooks:
    • X-Desk-Timestamp: Unix seconds, within 5 minutes of the desk's clock.
    • X-Desk-Signature: sha256= followed by the hex HMAC-SHA256 of <timestamp>.<raw body>, keyed with the secret.
import { createHmac } from 'node:crypto';

const body = JSON.stringify(alert);
const ts = Math.floor(Date.now() / 1000).toString();
const signature = 'sha256=' + createHmac('sha256', secret).update(`${ts}.${body}`).digest('hex');
await fetch(address, { method: 'POST', body, headers: { 'content-type': 'application/json', 'x-desk-timestamp': ts, 'x-desk-signature': signature } });

After a new secret is given with the old one kept, both secrets work for 24 hours.

Managing integrations​

These need a token with integration.read to read, and integration.settings to change. Neither comes with admin:all: name them on the token. Secrets and credentials are never in an answer, except a new endpoint's secret, once.

Method and pathWhat it does
GET /api/v1/integrationsThe integrations, with their endpoint count, last call and failed calls today.
GET /api/v1/integrations/metaThe connectors, the targets an endpoint can feed (with their fields), and the sign-in kinds.
POST /api/v1/integrations{ orgId, name, description?, connector? }. Creates the integration with its first endpoint, and answers with { id, endpoint: { id, address, secret } }.
GET /api/v1/integrations/{id}One integration with its endpoints (addresses, today's counts), connection and webhooks.
PATCH /api/v1/integrations/{id}name, description, enabled.
DELETE /api/v1/integrations/{id}Deletes it, its endpoints and its log. Linked webhooks stay, unlinked.
POST /api/v1/integrations/{id}/endpointsA new endpoint (the fields below). Answers with its address and secret.
PATCH /api/v1/integrations/endpoints/{id}Changes only the fields given.
DELETE /api/v1/integrations/endpoints/{id}Deletes the endpoint. Its calls stay in the log.
POST /api/v1/integrations/endpoints/{id}/secret{ immediately?: boolean }. A new secret. The old one keeps working for 24 hours unless immediately is true.
POST /api/v1/integrations/endpoints/{id}/test{ body? }. What the body (the sample when none is given) would do, changing nothing: { results, paths }.
POST /api/v1/integrations/paths{ sample, itemsPath? }. The placeholders a sample offers, each with an example value.
PUT /api/v1/integrations/{id}/connection{ baseUrl, auth, credentials?, headers?, timeoutMs? }. Leave out credentials to keep the stored ones (when auth stays the same).
DELETE /api/v1/integrations/{id}/connectionRemoves the connection.
POST /api/v1/integrations/{id}/connection/test{ path? }. A GET through the connection. The call is logged.
GET /api/v1/integrations/{id}/callsThe log, paged, filtered by direction, outcome and endpointId.
GET /api/v1/integrations/calls/{callId}One call, with its body.
POST /api/v1/integrations/calls/{callId}/replayHandles an accepted incoming call again, as a new call.
GET /api/v1/integrations/{id}/calls.exportThe log of a period (from, to, format = csv, xlsx or pdf).

An endpoint's fields:

FieldType
nametext
authbearer, basic or hmac
targetcase, or a plugin's target such as events.event or incidents.incident (from meta)
unitIda unit of the organization, or null
fields{ fieldId: template }
itemsPath, idempotencyPathpaths, or null
rateLimitcalls a minute, 1 to 6000
ipListIdone of the organization's IP allowlists, or null
sampleany JSON
captureNext, enabledtrue or false

Assistants reach all of this through the MCP server's call_endpoint.