Webhooks

Subscribe to real-time events delivered to your HTTPS endpoint. Webhooks notify your application whenever something happens in a project — tasks created, statuses changed, comments posted, and more.

Management Endpoints

MethodPathScopeDescription
GET/webhookswebhooks.manageList endpoints
POST/webhookswebhooks.manageSubscribe
GET/webhooks/:idwebhooks.manageGet detail + recent deliveries
PATCH/webhooks/:idwebhooks.manageUpdate
DELETE/webhooks/:idwebhooks.manageDelete
POST/webhooks/:id/pingwebhooks.manageSend test event

Subscribing

curl -X POST https://projects.cyrus365.com/api/v1/webhooks \

-H "Authorization: Bearer cyp_pub_xxxx" \

-H "Content-Type: application/json" \

-d '{

"url": "https://your-app.com/webhooks/projects",

"events": ["task.created", "task.updated", "task.status_changed"]

}'

The response includes a secret field (shown only once) — save it for signature verification.

Event Types

EventFired When
task.createdNew task created
task.updatedTask fields updated
task.deletedTask deleted
task.status_changedTask status changed
task.assignedAssignees changed
task.movedTask moved between groups/sprints
comment.createdNew comment on a task
sprint.createdSprint created
sprint.updatedSprint updated
sprint.status_changedSprint status changed
group.createdGroup created
group.updatedGroup updated
project.updatedProject details changed
project.deletedProject deleted
*Subscribe to all events
> Note: Subtask, tag, and attachment operations do not currently trigger webhook events.

Webhook Payload

{
    "id": "evt_abc123",
    "event": "task.created",
    "timestamp": "2025-01-15T10:30:00.000Z",
    "projectId": "clxyz...",
    "data": {
        "task": { "id": "...", "title": "...", "status": "TODO" }
    }
}

Signature Verification

All deliveries are signed with HMAC-SHA256. Verify the X-Webhook-Signature header against the raw JSON body using your endpoint's secret.

JavaScript

const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
    const expected = crypto

.createHmac("sha256", secret)

.update(payload, "utf8")

.digest("hex");

const received = signature.replace("sha256=", ""); return crypto.timingSafeEqual( Buffer.from(expected, "hex"), Buffer.from(received, "hex")

);

}

// Usage: const isValid = verifyWebhook(rawBody, req.headers["x-webhook-signature"], secret);

Python

import hmac, hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:

expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()

received = signature.replace("sha256=", "")

return hmac.compare_digest(expected, received)

Delivery Headers

HeaderDescription
X-Webhook-Signaturesha256=<hex> HMAC-SHA256 of the JSON body
X-Webhook-EventEvent type string
X-Webhook-IDUnique event ID (for idempotency)
X-Webhook-TimestampISO 8601 event timestamp
User-AgentCyrus365-Projects/1.0

Delivery Behavior

BehaviorDetail
Timeout10 seconds per attempt
Retries3 attempts — 1 s, 10 s, 60 s backoff
Auto-disableAfter 10 consecutive failures
Re-enablePATCH /webhooks/:id with { "isActive": true }
Max endpoints10 per API key

Related

  • API Overview — Base URL, response format, and error codes
  • Endpoints — All available API endpoints