Replace a key with a new secret carrying the same authority
const url = 'https://api.vocapable.com/v1/api-keys/example/rotate';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"example","expires_at":"2026-04-15T12:00:00Z"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.vocapable.com/v1/api-keys/example/rotate \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "example", "expires_at": "2026-04-15T12:00:00Z" }'Retire one key and mint its replacement, in one transaction.
Rotation exists because the two-call alternative - create, then delete - has no
safe order. Create-then-delete leaves both live if the second call is lost;
delete-then-create leaves the integration with no credential at all. Here the
revoke is the claim (revoke_returning), so a lost response leaves exactly one
live key and a replaying client gets 404 api_key_not_found rather than a second
replacement.
The replacement carries the retired key’s mode and scopes, not the caller’s.
That is what lets a narrow contractor key rotate itself without the caller having to
hold what it holds - and it is why the request body has no scopes field: there is
no widening path here to guard, only one that does not exist.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”Replace one key with another carrying the same authority.
Mode and scopes are deliberately not settable here: rotation replaces a
credential, it does not re-grant one. Widening on rotate would route around the
scope-escalation refusal POST /v1/api-keys makes.
Examplegenerated
{ "name": "example", "expires_at": "2026-04-15T12:00:00Z"}Responses
Section titled “Responses”Successful Response
The replacement key, plus the id of the credential it retired.
Both halves in one body because they happen in one transaction: a client that stored the new secret and never learned which key stopped working would have to diff a list to find out.
object
Example
{ "mode": "live"}Validation Error
object
object
object
Examplegenerated
{ "detail": [ { "loc": [ "example" ], "msg": "example", "type": "example", "input": "example", "ctx": {} } ]}