SpedySpedy Docs

Webhook Endpoints

Subscribe to events and receive real-time HTTP notifications when things happen in your organization.

Webhook endpoints let you receive HTTP callbacks when events occur in your organization -- for example, when a ticket is created or a status changes. You register a URL, choose which events to subscribe to, and Spedy sends a signed POST request to your URL whenever a matching event fires.

Webhook endpoints require a Pro plan subscription.

Supported Events

GET /api/v1/webhook-endpoints/events

Returns the list of event types you can subscribe to.

Available Events

EventDescription
ticket.createdA ticket was created
ticket.updatedA ticket was updated
ticket.deletedA ticket was deleted
ticket.status_changedA ticket's status changed
ticket.assignedA ticket was assigned or reassigned
ticket.claimedAn agent (or a person) took an exclusive lease on a ticket
ticket.claim_releasedA lease was handed back
ticket.claim_expiredA lease ran out without being released and the ticket became claimable again
ticket.reportedAn agent reported a run back via the tickets_report MCP tool
comment.createdA comment was added to a ticket
pr.openedA pull request appeared for the first time
pr.status_changedA pull request's state, pipeline status or review status changed
pr.mergedA pull request was merged
pipeline.updatedA CI/CD run was ingested or changed status

Payloads

Every delivery has the same envelope; only data differs per event:

{
  "id": "evt_...",
  "event": "ticket.claimed",
  "timestamp": "2026-09-02T10:00:00.000Z",
  "organizationId": "org_...",
  "data": { }
}

The whole body is signed with the endpoint's secret and sent as X-Spedy-Signature-256: sha256=<hex>; X-Spedy-Event and X-Spedy-Delivery carry the event name and the delivery id.

data carries identifiers and state, never content. A webhook receiver sits outside Spedy's permission model, so no comment body and no ticket description ever leaves through this channel -- comment.created gives you a commentId and an isSecret flag, and you read the comment through the API with a token that is actually authorised for it.

Eventdata fields
ticket.* (all)ticketId, boardId, projectId (legacy alias of boardId), organizationId
ticket.updated+ actorId
ticket.status_changed+ oldStatusId, newStatusId, actorId
ticket.assigned+ oldAssigneeId, newAssigneeId
ticket.claimed+ claimedById, claimExpiresAt, claimCount
ticket.claim_released+ releasedById, previousClaimedById, reason
ticket.claim_expired+ previousClaimedById, claimExpiresAt
ticket.reported+ actorId, outcome, summary, prUrl, branch, statusChanged, claimReleased, clientName
comment.created+ commentId, authorId, isSecret
pr.opened / pr.status_changed / pr.mergedprId, ticketId, boardId, organizationId, provider, repositoryFullName, externalNumber, title, url, sourceBranch, state, pipelineStatus, reviewStatus, requiresHumanReview
pipeline.updatedpipelineId, boardId, provider, repositoryFullName, providerPipelineId, ref, status, webUrl, pullRequestId

ticketId on the PR events is null when no ticket key could be resolved from the branch or title. pr.opened fires once, on the first webhook that creates the pull-request record -- the periodic background sync deliberately emits nothing, so connecting a repository with 200 open PRs does not fire 200 events.

Waking an agent loop

ticket.assigned is the intended wake-up signal for a loop that would rather not poll: assign a ticket to an agent user, receive the event, and have the loop claim the ticket immediately instead of waiting for the next tickets_list { claimable: true } tick. Combine it with ticket.claimed / ticket.claim_expired if you run several loops and want to see the handover. See Agent loops.

List Webhook Endpoints

GET /api/v1/webhook-endpoints

Permission required: webhooks:view

Returns all webhook endpoints configured for your organization.

Example Response

[
  {
    "id": "wh_abc123",
    "name": "CI/CD Pipeline",
    "url": "https://ci.example.com/hooks/spedy",
    "events": ["ticket.status_changed", "ticket.created"],
    "isActive": true,
    "createdAt": "2025-06-01T10:00:00Z",
    "updatedAt": "2025-06-01T10:00:00Z"
  }
]

Create Webhook Endpoint

POST /api/v1/webhook-endpoints

Permission required: webhooks:manage

Creates a new webhook endpoint. The response includes a secret field -- store this securely, as it is only returned once. Use the secret to verify the signature of incoming payloads.

Request Body

FieldTypeRequiredDescription
namestringYesDisplay name (max 100 characters)
urlstringYesThe HTTPS URL to receive webhook payloads
eventsstring[]YesArray of event types to subscribe to

Example Request

{
  "name": "CI/CD Pipeline",
  "url": "https://ci.example.com/hooks/spedy",
  "events": ["ticket.created", "ticket.status_changed"]
}

Example Response

{
  "id": "wh_abc123",
  "name": "CI/CD Pipeline",
  "url": "https://ci.example.com/hooks/spedy",
  "events": ["ticket.created", "ticket.status_changed"],
  "isActive": true,
  "secret": "whsec_a1b2c3d4e5...",
  "createdAt": "2025-06-01T10:00:00Z",
  "updatedAt": "2025-06-01T10:00:00Z"
}

Get Webhook Endpoint

GET /api/v1/webhook-endpoints/{id}

Permission required: webhooks:view

Returns details for a specific webhook endpoint.

Update Webhook Endpoint

PATCH /api/v1/webhook-endpoints/{id}

Permission required: webhooks:manage

Updates the name, URL, or subscribed events of a webhook endpoint.

Delete Webhook Endpoint

DELETE /api/v1/webhook-endpoints/{id}

Permission required: webhooks:manage

Returns 204 No Content.

Ping Webhook Endpoint

POST /api/v1/webhook-endpoints/{id}/ping

Permission required: webhooks:manage

Sends a test ping to the webhook URL to verify connectivity. Returns 204 No Content.

List Deliveries

GET /api/v1/webhook-endpoints/{id}/deliveries

Permission required: webhooks:view

Returns recent delivery attempts for a webhook endpoint.

Query Parameters

ParameterTypeRequiredDescription
limitnumberNoNumber of deliveries to return (default: 50, max: 200)

Example Response

[
  {
    "id": "dlv_xyz789",
    "endpointId": "wh_abc123",
    "eventType": "ticket.created",
    "statusCode": 200,
    "success": true,
    "attempt": 1,
    "error": null,
    "createdAt": "2025-06-15T14:30:00Z"
  }
]

Redeliver

POST /api/v1/webhook-endpoints/{id}/deliveries/{deliveryId}/redeliver

Permission required: webhooks:manage

Re-sends a previous webhook delivery. Returns 204 No Content.