A valid request URL is required to generate request examples{
"apiKeyId": "<string>",
"keyId": "<string>",
"name": "<string>",
"scopes": [
"devices:read"
],
"deviceIds": [
"<string>"
],
"createdBy": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"expiresAt": "2023-11-07T05:31:56Z",
"revokedAt": "2023-11-07T05:31:56Z",
"lastUsedAt": "2023-11-07T05:31:56Z",
"rotatedFrom": "<string>",
"token": "<string>",
"oldKeyExpiresAt": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Rotate a key
Mints a successor key with the same name, scopes and device subset (fresh lifetime, fresh secret) and shortens the old key’s expiry to the grace deadline, atomically. The successor’s token appears ONCE, in this response, exactly like creation.
Grace: the old key keeps working for graceMs (default 86400000 ms = 24 hours, 0 = immediately dead, at most 72 hours), then answers 401 as expired. Grace never EXTENDS a key: one that would expire sooner keeps its earlier deadline, and rotating an already-expired key leaves it expired (rotation is the documented way back from an expired key).
Hosted deployments only. A local checkout does not mount this route, so calling it there is a 404.
A valid request URL is required to generate request examples{
"apiKeyId": "<string>",
"keyId": "<string>",
"name": "<string>",
"scopes": [
"devices:read"
],
"deviceIds": [
"<string>"
],
"createdBy": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"expiresAt": "2023-11-07T05:31:56Z",
"revokedAt": "2023-11-07T05:31:56Z",
"lastUsedAt": "2023-11-07T05:31:56Z",
"rotatedFrom": "<string>",
"token": "<string>",
"oldKeyExpiresAt": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Authorizations
The control surface credential. Send Authorization: Bearer <token>.
Two kinds of token are accepted and they are told apart by shape, not by a separate header. A token beginning pbk_ is an org scoped API key, whose public half and secret half are generated together and of which only a hash of the secret is ever stored; anything else is treated as an OAuth 2.1 access token and verified against the authorization server's keys.
Both resolve to the same context: an org, a principal and a set of scopes. Nothing downstream branches on which channel you used, with one deliberate exception, key management, which requires a signed-in person so that a key can never mint another key.
Scopes are enforced when MCP tools are REGISTERED rather than when they are called, so a tool your credential cannot use is absent from tools/list rather than refused mid gesture.
Path Parameters
The apiKeyId from a listing, not the token and not the keyId.
Body
Optional grace and successor lifetime; omit the body for the defaults.
Response
The successor was minted; the old key now dies at oldKeyExpiresAt. This response is the ONLY time the successor's token is returned.
The summary, plus the one and only time the token itself leaves the service.
The key's own id. This is what you pass to revoke it.
The public half of the token, the part before the secret.
A granted scope.
devices:read, devices:act, devices:lease, runs:start, orders:place, apps:read, apps:write, apps:delete The device subset this key may see and address, or null for the whole org.
Updated off the request path, so it can lag slightly behind the last real use.
The apiKeyId this key replaced via rotation, or null for keys minted directly.
The full bearer token. Shown here ONCE and never stored in recoverable form.
When the rotated-out key stops working.