Webhooks
Outbound, signed webhooks and their delivery log.
| Operation | Method and path |
|---|---|
| List webhooks | GET /v1/workspaces/{workspace}/webhooks |
| Create a webhook | POST /v1/workspaces/{workspace}/webhooks |
| Get a webhook | GET /v1/workspaces/{workspace}/webhooks/{webhook_id} |
| Update a webhook | PATCH /v1/workspaces/{workspace}/webhooks/{webhook_id} |
| Delete a webhook | DELETE /v1/workspaces/{workspace}/webhooks/{webhook_id} |
| Rotate the signing secret | POST /v1/workspaces/{workspace}/webhooks/{webhook_id}/rotate-secret |
| Send a test event | POST /v1/workspaces/{workspace}/webhooks/{webhook_id}/test |
| Delivery log | GET /v1/workspaces/{workspace}/webhooks/{webhook_id}/deliveries |
| Redeliver an event | POST /v1/workspaces/{workspace}/webhooks/{webhook_id}/deliveries/{delivery_id}/redeliver |
List webhooks
Section titled “List webhooks”GET /v1/workspaces/{workspace}/webhooks- Operation:
listWebhooks - Scopes:
webhooks:read - Paginated:
?limit=and?cursor=
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of Webhook objects. | WebhookList |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme/webhooks \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "id": "whk_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "url": "https://guv.dev/", "description": "string", "events": [ "deployment.created" ], "project_ids": [ "string" ], "enabled": false, "secret_prefix": "whsec_Ab3d", "last_delivery": { "status": "string", "at": "2026-10-22T13:05:00Z" }, "created_at": "2026-10-22T13:05:00Z", "updated_at": "2026-10-22T13:05:00Z" } ], "next_cursor": "string", "has_more": false}Create a webhook
Section titled “Create a webhook”POST /v1/workspaces/{workspace}/webhooksThe signing secret is returned once.
- Operation:
createWebhook - Scopes:
webhooks:write - Idempotency-Key: required; supports
?dry_run=true
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
Request body (application/json, required): WebhookCreate
| Field | Type | Description |
|---|---|---|
url * |
string (uri) | |
description |
string | |
events * |
array of WebhookEventType | |
project_ids |
array of string or null | |
enabled |
boolean | Default true. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
Dry run. Nothing was changed; this is what would happen. | Plan |
201 Created |
Created. | WebhookCreated |
Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/workspaces/acme/webhooks \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "url": "https://guv.dev/", "description": "string", "events": [ "deployment.created" ], "project_ids": [ "string" ], "enabled": true}'Example response
{ "id": "whk_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "url": "https://guv.dev/", "description": "string", "events": [ "deployment.created" ], "project_ids": [ "string" ], "enabled": false, "secret_prefix": "whsec_Ab3d", "last_delivery": { "status": "string", "at": "2026-10-22T13:05:00Z" }, "created_at": "2026-10-22T13:05:00Z", "updated_at": "2026-10-22T13:05:00Z", "secret": "string"}Get a webhook
Section titled “Get a webhook”GET /v1/workspaces/{workspace}/webhooks/{webhook_id}- Operation:
getWebhook - Scopes:
webhooks:read
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Webhook |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "id": "whk_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "url": "https://guv.dev/", "description": "string", "events": [ "deployment.created" ], "project_ids": [ "string" ], "enabled": false, "secret_prefix": "whsec_Ab3d", "last_delivery": { "status": "string", "at": "2026-10-22T13:05:00Z" }, "created_at": "2026-10-22T13:05:00Z", "updated_at": "2026-10-22T13:05:00Z"}Update a webhook
Section titled “Update a webhook”PATCH /v1/workspaces/{workspace}/webhooks/{webhook_id}- Operation:
updateWebhook - Scopes:
webhooks:write - Idempotency-Key: required; supports
?dry_run=true - Concurrency: send the
ETagyou read asIf-Match
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string |
Request body (application/json, required): WebhookUpdate
| Field | Type | Description |
|---|---|---|
url |
string (uri) | |
description |
string | |
events |
array of WebhookEventType | |
project_ids |
array of string or null | |
enabled |
boolean |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. With dry_run=true: a Plan (application/vnd.guv.plan+json) and nothing changes. |
Webhook |
Errors: 400, 401, 403, 404, 409, 412, 422, 429, 500, as problem+json with a stable code.
Example
curl -X PATCH https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "url": "https://guv.dev/", "description": "string", "events": [ "deployment.created" ], "project_ids": [ "string" ], "enabled": false}'Example response
{ "id": "whk_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "url": "https://guv.dev/", "description": "string", "events": [ "deployment.created" ], "project_ids": [ "string" ], "enabled": false, "secret_prefix": "whsec_Ab3d", "last_delivery": { "status": "string", "at": "2026-10-22T13:05:00Z" }, "created_at": "2026-10-22T13:05:00Z", "updated_at": "2026-10-22T13:05:00Z"}Delete a webhook
Section titled “Delete a webhook”DELETE /v1/workspaces/{workspace}/webhooks/{webhook_id}- Operation:
deleteWebhook - Scopes:
webhooks:write - Idempotency-Key: required; supports
?dry_run=true - Concurrency: send the
ETagyou read asIf-Match
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
Dry run. Nothing was changed; this is what would happen. | Plan |
204 No Content |
Done. No body. | none |
Errors: 400, 401, 403, 404, 409, 412, 422, 429, 500, as problem+json with a stable code.
Example
curl -X DELETE https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Rotate the signing secret
Section titled “Rotate the signing secret”POST /v1/workspaces/{workspace}/webhooks/{webhook_id}/rotate-secretThe old secret keeps working for 24 hours.
- Operation:
rotateWebhookSecret - Scopes:
webhooks:write - Idempotency-Key: required
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | WebhookSecret |
Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr/rotate-secret \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Example response
{ "secret": "string"}Send a test event
Section titled “Send a test event”POST /v1/workspaces/{workspace}/webhooks/{webhook_id}/test- Operation:
testWebhook - Scopes:
webhooks:write - Idempotency-Key: required
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
201 Created |
Created. | WebhookDelivery |
Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr/test \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Example response
{ "id": "whd_01jbx2m9k7q4r8t5v6w3y0z1pr", "webhook_id": "string", "event_id": "string", "event_type": "deployment.created", "attempt": 1, "status": "pending", "request": { "headers": { "key": "string" }, "body": "string" }, "response": { "status": 1, "body_excerpt": "string", "duration_ms": 1 }, "next_attempt_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z", "delivered_at": "2026-10-22T13:05:00Z"}Delivery log
Section titled “Delivery log”GET /v1/workspaces/{workspace}/webhooks/{webhook_id}/deliveries- Operation:
listWebhookDeliveries - Scopes:
webhooks:read - Paginated:
?limit=and?cursor=
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string | |
status |
query | pending, succeeded, failed, retrying |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of WebhookDelivery objects. | WebhookDeliveryList |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr/deliveries \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "id": "whd_01jbx2m9k7q4r8t5v6w3y0z1pr", "webhook_id": "string", "event_id": "string", "event_type": "deployment.created", "attempt": 1, "status": "pending", "request": { "headers": { "key": "string" }, "body": "string" }, "response": { "status": 1, "body_excerpt": "string", "duration_ms": 1 }, "next_attempt_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z", "delivered_at": "2026-10-22T13:05:00Z" } ], "next_cursor": "string", "has_more": false}Redeliver an event
Section titled “Redeliver an event”POST /v1/workspaces/{workspace}/webhooks/{webhook_id}/deliveries/{delivery_id}/redeliver- Operation:
redeliverWebhook - Scopes:
webhooks:write - Idempotency-Key: required
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
webhook_id * |
path | string | |
delivery_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
201 Created |
Created. | WebhookDelivery |
Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/workspaces/acme/webhooks/web_01jbx2m9k7q4r8t5v6w3y0z1pr/deliveries/del_01jbx2m9k7q4r8t5v6w3y0z1pr/redeliver \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Example response
{ "id": "whd_01jbx2m9k7q4r8t5v6w3y0z1pr", "webhook_id": "string", "event_id": "string", "event_type": "deployment.created", "attempt": 1, "status": "pending", "request": { "headers": { "key": "string" }, "body": "string" }, "response": { "status": 1, "body_excerpt": "string", "duration_ms": 1 }, "next_attempt_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z", "delivered_at": "2026-10-22T13:05:00Z"}Event delivered to your webhook endpoint
Section titled “Event delivered to your webhook endpoint”Sent for each subscribed event type. Respond 2xx within 10 seconds. Failed deliveries are retried with exponential backoff for 24 hours and appear in the delivery log.
Headers Guv sends
| Header | Description |
|---|---|
Guv-Signature |
t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>"> |
Guv-Event-Id |
|
Guv-Delivery-Id |
Body: WebhookEvent
| Field | Type | Description |
|---|---|---|
id * |
string | |
type * |
WebhookEventType | |
api_version |
string | |
created_at * |
string (date-time) | |
workspace_id * |
string | |
project_id |
string or null | |
data * |
object | The resource the event is about (for example a Deployment), as returned by the API. |
Example payload
{ "id": "evt_01jbx2m9k7q4r8t5v6w3y0z1ev", "type": "deployment.succeeded", "api_version": "2026-11-01", "created_at": "2026-10-23T14:05:12Z", "workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "project_id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr", "data": { "id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp", "status": "active", "service_name": "web", "environment_name": "production" }}