Webhook-Endpunkte
Events abonnieren und Echtzeit-HTTP-Benachrichtigungen empfangen, wenn in deiner Organisation etwas passiert.
Webhook-Endpunkte ermoglichen es dir, HTTP-Callbacks zu empfangen, wenn Events in deiner Organisation auftreten -- zum Beispiel wenn ein Ticket erstellt oder ein Status geandert wird. Du registrierst eine URL, wahlst die Events aus, die du abonnieren mochtest, und Spedy sendet einen signierten POST-Request an deine URL, wenn ein passendes Event ausgelost wird.
Webhook-Endpunkte erfordern ein Pro-Plan-Abonnement.
Unterstuetzte Events
GET /api/v1/webhook-endpoints/eventsGibt die Liste der Event-Typen zurueck, die du abonnieren kannst.
Verfuegbare Events
| Event | Beschreibung |
|---|---|
ticket.created | Ein Ticket wurde erstellt |
ticket.updated | Ein Ticket wurde aktualisiert |
ticket.deleted | Ein Ticket wurde geloescht |
ticket.status_changed | Der Status eines Tickets wurde geaendert |
ticket.assigned | Ein Ticket wurde zugewiesen oder neu zugewiesen |
ticket.claimed | Ein Agent (oder ein Mensch) hat ein Ticket exklusiv geclaimt |
ticket.claim_released | Ein Claim wurde zurueckgegeben |
ticket.claim_expired | Ein Claim ist abgelaufen, ohne zurueckgegeben zu werden -- das Ticket ist wieder claimbar |
ticket.reported | Ein Agent hat einen Lauf per MCP-Tool tickets_report zurueckgemeldet |
comment.created | Ein Kommentar wurde zu einem Ticket hinzugefuegt |
pr.opened | Ein Pull Request ist zum ersten Mal aufgetaucht |
pr.status_changed | Status, Pipeline- oder Review-Status eines Pull Requests hat sich geaendert |
pr.merged | Ein Pull Request wurde gemerged |
pipeline.updated | Ein CI/CD-Lauf wurde eingelesen oder hat den Status gewechselt |
Payloads
Jede Zustellung hat denselben Umschlag, nur data unterscheidet sich pro Event:
{
"id": "evt_...",
"event": "ticket.claimed",
"timestamp": "2026-09-02T10:00:00.000Z",
"organizationId": "org_...",
"data": { }
}Der gesamte Body wird mit dem Secret des Endpunkts signiert und als
X-Spedy-Signature-256: sha256=<hex> gesendet; X-Spedy-Event und
X-Spedy-Delivery tragen Eventnamen und Delivery-ID.
data enthaelt IDs und Status, niemals Inhalte. Ein Webhook-Empfaenger
steht ausserhalb des Berechtigungsmodells von Spedy -- deshalb verlaesst weder
ein Kommentartext noch eine Ticketbeschreibung diesen Kanal.
comment.created liefert eine commentId und ein isSecret-Flag; den
Kommentar selbst liest du ueber die API mit einem Token, das dafuer auch
berechtigt ist.
| Event | Felder in data |
|---|---|
ticket.* (alle) | ticketId, boardId, projectId (Alt-Alias von 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.merged | prId, ticketId, boardId, organizationId, provider, repositoryFullName, externalNumber, title, url, sourceBranch, state, pipelineStatus, reviewStatus, requiresHumanReview |
pipeline.updated | pipelineId, boardId, provider, repositoryFullName, providerPipelineId, ref, status, webUrl, pullRequestId |
ticketId ist bei den PR-Events null, wenn aus Branch oder Titel kein
Ticket-Key aufloesbar war. pr.opened feuert genau einmal -- beim ersten
Webhook, der den Pull-Request-Datensatz anlegt. Der periodische Hintergrund-Sync
emittiert bewusst nichts, damit das Verbinden eines Repos mit 200 offenen PRs
nicht 200 Events ausloest.
Einen Agenten-Loop wecken
ticket.assigned ist der vorgesehene Weckruf fuer einen Loop, der nicht
pollen will: Ticket einem Agenten-User zuweisen, Event empfangen, Loop claimt
sofort -- statt auf den naechsten tickets_list { claimable: true }-Tick zu
warten. In Kombination mit ticket.claimed / ticket.claim_expired siehst du
die Uebergabe zwischen mehreren Loops.
Siehe Agenten-Loops.
Webhook-Endpunkte auflisten
GET /api/v1/webhook-endpointsBerechtigung erforderlich: webhooks:view
Gibt alle Webhook-Endpunkte zurueck, die fuer deine Organisation konfiguriert sind.
Beispiel-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"
}
]Webhook-Endpunkt erstellen
POST /api/v1/webhook-endpointsBerechtigung erforderlich: webhooks:manage
Erstellt einen neuen Webhook-Endpunkt. Die Antwort enthaelt ein secret-Feld -- speichere es sicher, da es nur einmal zurueckgegeben wird. Verwende das Secret, um die Signatur eingehender Payloads zu verifizieren.
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| name | string | Ja | Anzeigename (max. 100 Zeichen) |
| url | string | Ja | Die HTTPS-URL zum Empfang von Webhook-Payloads |
| events | string[] | Ja | Array von Event-Typen zum Abonnieren |
Beispiel-Request
{
"name": "CI/CD Pipeline",
"url": "https://ci.example.com/hooks/spedy",
"events": ["ticket.created", "ticket.status_changed"]
}Beispiel-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"
}Webhook-Endpunkt abrufen
GET /api/v1/webhook-endpoints/{id}Berechtigung erforderlich: webhooks:view
Gibt Details zu einem bestimmten Webhook-Endpunkt zurueck.
Webhook-Endpunkt aktualisieren
PATCH /api/v1/webhook-endpoints/{id}Berechtigung erforderlich: webhooks:manage
Aktualisiert den Namen, die URL oder die abonnierten Events eines Webhook-Endpunkts.
Webhook-Endpunkt loeschen
DELETE /api/v1/webhook-endpoints/{id}Berechtigung erforderlich: webhooks:manage
Gibt 204 No Content zurueck.
Webhook-Endpunkt pingen
POST /api/v1/webhook-endpoints/{id}/pingBerechtigung erforderlich: webhooks:manage
Sendet einen Test-Ping an die Webhook-URL, um die Erreichbarkeit zu pruefen. Gibt 204 No Content zurueck.
Zustellungen auflisten
GET /api/v1/webhook-endpoints/{id}/deliveriesBerechtigung erforderlich: webhooks:view
Gibt die letzten Zustellversuche fuer einen Webhook-Endpunkt zurueck.
Query-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| limit | number | Nein | Anzahl der zurueckzugebenden Zustellungen (Standard: 50, max. 200) |
Beispiel-Response
[
{
"id": "dlv_xyz789",
"endpointId": "wh_abc123",
"eventType": "ticket.created",
"statusCode": 200,
"success": true,
"attempt": 1,
"error": null,
"createdAt": "2025-06-15T14:30:00Z"
}
]Erneut zustellen
POST /api/v1/webhook-endpoints/{id}/deliveries/{deliveryId}/redeliverBerechtigung erforderlich: webhooks:manage
Sendet eine vorherige Webhook-Zustellung erneut. Gibt 204 No Content zurueck.