Skip to main content
Version: 1.1.5

Webhooks API

The Webhooks API allows you to register callback URLs that receive notifications when specific events occur in the Symphony system. This enables real-time integrations with external services like CI/CD pipelines, chat platforms, analytics tools, and audit systems.

Data model

FieldTypeDescription
idstringUnique identifier (e.g. wh_a1b2c3d4)
urlstringCallback URL that receives event payloads
eventsstring[]Array of event types this webhook subscribes to
secretstringShared secret for signing payloads (redacted in read responses)
activebooleanWhether the webhook is currently enabled
descriptionstringHuman-readable description of the webhook's purpose
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last-update timestamp

Supported events

EventDescription
project.createdNew project created
project.updatedProject modified
project.deletedProject deleted
task.createdNew task created
task.updatedTask modified
task.deletedTask deleted
comment.createdNew comment posted
comment.updatedComment modified
comment.deletedComment deleted
milestone.reachedProject milestone achieved
sprint.startedSprint initiated
sprint.completedSprint finished
*Wildcard — subscribe to all event types

Secret handling

For security, webhook secrets are:

  • Auto-generated when you create a webhook (format: whsec_<12-char-alphanumeric>)
  • Returned once in the POST response
  • Redacted from all subsequent GET and PATCH responses

Store the secret securely after creation — you cannot retrieve it again through the API.

Endpoints

List webhooks

GET /api/webhooks

Query parameters:

ParameterTypeDescription
activestringFilter by active status ("true" or "false")
eventstringFilter to webhooks subscribed to this event type (includes wildcard subscribers)

Response: 200 OK

{
"data": [
{
"id": "wh_01",
"url": "https://ci.example.com/hooks/symphony",
"events": ["task.created", "task.updated"],
"active": true,
"description": "CI pipeline trigger on task changes",
"createdAt": "2025-11-10T09:00:00Z",
"updatedAt": "2025-11-10T09:00:00Z"
}
],
"count": 1
}

Note: The secret field is omitted from list responses.

Get webhook

GET /api/webhooks/:id

Response: 200 OK with the webhook object (secret redacted).

Error: 404 Not Found with error code NOT_FOUND if the webhook does not exist.

Create webhook

POST /api/webhooks

Request body:

{
"url": "https://slack.example.com/api/webhook",
"events": ["project.updated", "milestone.reached"],
"description": "Slack notifications for project milestones",
"active": true
}
FieldRequiredDefault
urlyes
eventsno[]
descriptionno""
activenotrue

Event validation: All event types in the events array must be valid (see supported events above). Invalid events return a 400 Bad Request with error code INVALID_EVENTS.

Response: 201 Created

{
"data": {
"id": "wh_a1b2c3d4",
"url": "https://slack.example.com/api/webhook",
"events": ["project.updated", "milestone.reached"],
"secret": "whsec_8f7e6d5c4b3a",
"active": true,
"description": "Slack notifications for project milestones",
"createdAt": "2026-02-19T10:00:00Z",
"updatedAt": "2026-02-19T10:00:00Z"
}
}

Important: The secret field is only returned in this response. Store it securely.

Update webhook

PATCH /api/webhooks/:id

Partially update a webhook. Only provided fields are updated. The id, secret, and createdAt fields are preserved.

Request body example:

{
"active": false,
"description": "Analytics ingestion (paused for maintenance)"
}

Event validation: If you update the events array, all event types must be valid. Invalid events return a 400 Bad Request with error code INVALID_EVENTS.

Response: 200 OK with the updated webhook (secret redacted).

Error: 404 Not Found with error code NOT_FOUND if the webhook does not exist.

Delete webhook

DELETE /api/webhooks/:id

Response: 200 OK

{
"data": {
"id": "wh_a1b2c3d4",
"deleted": true
}
}

Error: 404 Not Found with error code NOT_FOUND if the webhook does not exist.

Examples

Subscribe to all task events

curl -X POST http://localhost:3000/api/webhooks \
-H "Content-Type: application/json" \
-d '{
"url": "https://ci.example.com/hooks/symphony",
"events": ["task.created", "task.updated", "task.deleted"],
"description": "CI pipeline integration"
}'

Subscribe to all events with wildcard

curl -X POST http://localhost:3000/api/webhooks \
-H "Content-Type: application/json" \
-d '{
"url": "https://audit.example.com/events",
"events": ["*"],
"description": "Audit log — receives all events"
}'

Filter active webhooks subscribed to task creation

curl "http://localhost:3000/api/webhooks?active=true&event=task.created"

This returns both webhooks explicitly subscribed to task.created and those subscribed to * (wildcard).

Pause a webhook temporarily

curl -X PATCH http://localhost:3000/api/webhooks/wh_01 \
-H "Content-Type: application/json" \
-d '{"active": false}'