Rotate a webhook endpoint secret
/v1/webhook-endpoints/{endpoint_id}/rotate-secretCreate-overlap-revoke rotation: mints a NEW signing secret (returned ONCE, same as create) and moves the CURRENT secret to `previous_secret_expires_at`-bounded overlap — the worker signs every delivery with BOTH secrets during that ~24h window so you can finish updating your verifier without dropping deliveries. Rotating a SECOND time before the first rotation's grace window elapses immediately drops the FIRST previous secret (there is only ever one previous-secret slot, not a stack) — do not chain rotations faster than your own verifier can keep up. Never mutates a secret in place; always mints fresh. Supports the optional `Idempotency-Key` header (a replay returns the SAME newly-minted secret again, never rotates twice for one logical request).
Request
Path parameters
| Field | Type | Description |
|---|---|---|
endpoint_idrequired | string |
Response 200
The endpoint with its newly rotated secret.
Fields
| Field | Type | Description |
|---|---|---|
idrequired | string | Stable id of the endpoint. |
urlrequired | string | The https destination URL. |
enabledrequired | boolean | False when disabled — manually, or auto-disabled after repeated delivery failures (see `disabled_reason`). |
event_typesrequired | "task.created" | "task.updated" | "task.archived"[] | Subscribed event types. An EMPTY array means "every type". |
verifiedrequired | boolean | True once the `verify` action has proven this endpoint accepts a correctly-signed request. |
disabled_reasonrequired | string | null | Why the endpoint was auto-disabled, or null when never auto-disabled. |
created_atrequired | string (date-time) | ISO-8601 UTC. |
updated_atrequired | string (date-time) | ISO-8601 UTC. |
secretrequired | string | The NEW signing secret — shown EXACTLY ONCE.e.g. whsec_51f3...redacted |
previous_secret_expires_atrequired | string (date-time) | The prior secret keeps signing outgoing deliveries alongside the new one until this time (~24h out) — dual-secret acceptance so you can finish updating your verifier before the old secret dies. |
▸ ▾ Raw response schema
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Stable id of the endpoint."
},
"url": {
"type": "string",
"description": "The https destination URL."
},
"enabled": {
"type": "boolean",
"description": "False when disabled — manually, or auto-disabled after repeated delivery failures (see `disabled_reason`)."
},
"event_types": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WebhookEndpointEventType"
},
"description": "Subscribed event types. An EMPTY array means \"every type\"."
},
"verified": {
"type": "boolean",
"description": "True once the `verify` action has proven this endpoint accepts a correctly-signed request."
},
"disabled_reason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the endpoint was auto-disabled, or null when never auto-disabled."
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "ISO-8601 UTC."
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "ISO-8601 UTC."
},
"secret": {
"type": "string",
"description": "The NEW signing secret — shown EXACTLY ONCE.",
"example": "whsec_51f3...redacted"
},
"previous_secret_expires_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "The prior secret keeps signing outgoing deliveries alongside the new one until this time (~24h out) — dual-secret acceptance so you can finish updating your verifier before the old secret dies."
}
},
"required": [
"id",
"url",
"enabled",
"event_types",
"verified",
"disabled_reason",
"created_at",
"updated_at",
"secret",
"previous_secret_expires_at"
],
"additionalProperties": false,
"description": "Result of a create-overlap-revoke secret rotation. Rotating a SECOND time before the first rotation's grace window elapses immediately drops the FIRST previous secret — there is only ever one previous-secret slot, not a stack."
}Example request
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/rotate-secret \
-H "Authorization: Bearer gid_YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"Possible errors
- 400
validation_failedRequest validation failed - 401
missing_credentialsMissing credentials - 401
invalid_api_keyInvalid API key - 401
invalid_tokenInvalid access token - 403
insufficient_scopeInsufficient scope - 403
feature_not_enabledFeature not enabled on this plan - 404
resource_not_foundResource not found - 409
idempotency_in_progressA request with this Idempotency-Key is still in progress - 422
idempotency_key_reusedIdempotency-Key reused with a different request - 429
rate_limitedRate limit exceeded - 429
quota_exhaustedPlan quota exhausted - 500
internal_errorInternal server error