Browse the docs

Webhooks and Slack

Send work-item activity to a Slack channel or to your own HTTPS endpoint with signed JSON payloads.

Skopo can notify other systems whenever work changes in a project. Each project can have any number of hooks:

  • Slack: posts a readable message to a channel, such as "Ana moved REQ-12 Fix login to In review", with a link back to Skopo.
  • Generic webhook: sends a signed JSON POST to your own HTTPS endpoint.

Workspace owners and project leads can manage hooks.

Set up a hook

  1. Open Workspace → Integrations and scroll to Slack & webhooks.
  2. Choose the project.
  3. Pick Slack channel or Generic webhook and paste the URL.
    • For Slack, create an incoming webhook for the channel and paste its https://hooks.slack.com/services/... URL.
    • Generic URLs must use https.
  4. Choose which events to send and click Add.
  5. For a generic webhook, copy the signing secret right away. It's shown only once.
  6. Click Test to send a sample event. The hook's last delivery status and time appear in the list.

You can pause a hook by clearing Active, or delete it.

Events

EventSent when
work_item.createdA work item is created
work_item.updatedTitle, description, points, labels, or priority change
work_item.status_changedA work item moves to a different workflow state
work_item.assignedAssignees change
work_item.commentedSomeone comments
work_item.removedA work item is removed
webhook.testYou click Test

Generic payload

{
  "event": "work_item.status_changed",
  "project": { "id": "4f6c...", "publicId": "prj_S8qDRLbDJWbp", "key": "ACME", "name": "Acme web" },
  "issue": { "id": "9a1e...", "key": "REQ-12", "title": "Fix login", "displayRef": "#12 Request", "status": "review" },
  "changes": { "status": { "from": "inprogress", "to": "review" } },
  "comment": null,
  "actor": { "id": "user_123", "name": "Ana" },
  "url": "https://skopo.dev/p/prj_S8qDRLbDJWbp/dashboard?item=REQ-12",
  "occurredAt": "2026-10-16T12:00:00.000Z"
}

Request headers:

HeaderValue
Content-Typeapplication/json
X-Skopo-EventThe event name
X-Skopo-Signaturesha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with your signing secret

Verify the signature

Compute the HMAC over the raw body before you parse it, and compare it in constant time:

import { createHmac, timingSafeEqual } from "node:crypto";

function isFromSkopo(rawBody, header, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  return header.length === expected.length && timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

Delivery

  • Skopo sends each event once, right after the change is saved. Failed deliveries aren't retried.
  • Your endpoint must respond within 5 seconds. Any 2xx response counts as success.
  • Redirects aren't followed.
  • A failed delivery never blocks the change in Skopo.

To read or change work from your own code, use the REST API.