These are the calls an AI assistant or a command-line tool makes about itself: signing in, checking whether a person has approved something, and handing its own key back. None of them reads or changes anything in a workspace.
Signing in without pasting a key
A person should never have to copy a key out of a dashboard and into a config
file. POST /v1/auth/device is the alternative, and it inverts who holds the
secret:
- Your program makes the key. Thirty-two random bytes, rendered as 43
base62 characters, with
bc_live_in front. Keep it somewhere only you can read. - You send its hash.
key_hashis the SHA-256 of the whole string;key_prefixis the first 8 characters afterbc_live_, which is what a person sees in their list of connections. The key itself has no field to travel in. - A person approves it at
boltclaw.ai/auth/device, choosing the workspace and ticking the permissions they are willing to give. - You poll
POST /v1/auth/device/polleveryintervalseconds until it answersapproved. Then the key you already hold starts working.
denied and expired end it; start again. A device_code that was never
issued, or has been cleared away, answers expired exactly like one that
lapsed, so polling cannot be used to find out which codes exist.
The approval names the workspace the person chose, by id and name. That is one
of the very few answers in this API that carries a workspace id, and it is
answered only to the holder of the device_code: the program that started the
sign-in, whose new key belongs to that workspace.
So between the approval and your next poll there is no credential of ours to
lose, and a stolen device_code reveals one thing: whether the request was
approved.
Do not try the key before the poll says approved. Until a person decides,
that key does not exist, and it is refused exactly like any other key that does
not — which the API remembers for five minutes, to make guessing keys
expensive. A client that probes early therefore waits out those five minutes
after the approval before anything works. Poll, and use the key once the poll
tells you to.
Ask for the permissions you need and no more. The person sees the list, can untick any of it, and whatever survives is narrowed again to what they themselves may grant. Permissions an assistant may never hold — managing API keys, managing webhooks — are refused at step 1, not silently dropped at step 3.
Approvals
Some calls stop and ask. If you make one, you get a 428 whose body carries
an approval object:
{
"error": "Nothing has been done. A person must approve this action first...",
"code": "APPROVAL_REQUIRED",
"request_id": "...",
"approval": {
"id": "0c4b...",
"url": "https://boltclaw.ai/dashboard/approvals/0c4b...",
"expires_at": "2026-10-20T09:12:44.000Z",
"status": "pending"
}
}
Nothing has happened. Show the url to the person. When they approve it,
send the identical request again with the id in the BoltClaw-Approval
header. While you wait, GET /v1/approvals/{id} tells you where it has got to,
and it is cheap enough to poll.
The approval is bound to that exact request and to the state it acts on, so one approved for deleting a page cannot be spent on a different page, or on the same page after somebody renamed it. It is single use and it lapses after 24 hours.
Which calls ask, and whether an organisation can decide to stop being asked, is on Authentication and keys.
Keeping a key alive, and ending it
A key approved for an assistant lasts 90 days. POST /v1/auth/key/extend
pushes that out by another 90, up to a year from the day it was issued, and
only within the last 30 days of its life — so calling it on a schedule is safe
and usually answers extended: false. After a year, a person signs in again.
POST /v1/auth/key/revoke ends the calling key. Use it when somebody
disconnects your program, and when you uninstall: deleting a key from a
configuration file leaves it working, and this does not. It works even when an
organisation has turned assistant access off, because handing a credential back
must never be the thing you cannot do.
Both act only on the key that made the call, so neither needs a scope.
Operations
POST /v1/auth/device
Start a device sign-in
No scope: any valid key.
How an AI assistant or a command-line tool gets a key, without anybody pasting one.
Your program generates the key. Make 32 random bytes, render them as 43 base62
characters, prefix them with bc_live_, and send only the SHA-256 of the whole string
plus the first 8 characters of the random body. The key itself must never leave the
machine it was made on, and there is no field here that would carry it. BoltClaw stores
the hash, exactly as it stores every other key's, so no secret of ours exists at any
moment, not even between the approval and your next poll.
You get back a short code and a URL. Show both to the person, poll
POST /v1/auth/device/poll every interval seconds, and once they approve, the key you
already hold starts working.
Ask for the permissions you need and no more: the person sees them, can untick any of them, and the key is narrowed again to what they themselves may grant. Permissions an assistant may never hold, such as managing API keys or webhooks, are refused here rather than silently dropped later.
This call needs no API key, and it is limited per address rather than per key.
Request body (required)
| Field | Type | |
|---|---|---|
client_name |
string |
What you are called, shown to the person deciding. Never trusted for anything. (required; min 1; max 80) |
client_host |
string |
The machine you are running on, shown beside the name so a person can tell two terminals apart. (min 1; max 120) |
scopes |
Scope[] |
The permissions you are asking for. Ask for what you need and no more. (required; <= 25 items; >= 1 items) |
key_hash |
string |
(required) |
key_prefix |
string |
(required) |
flow |
string |
device for a program somebody is sitting at. oauth is the hosted BoltClaw MCP server acting for a person, and only it may ask for one. (default device; one of device, oauth) |
redirect_host |
string |
Only with flow: oauth. The host the person will be sent back to, shown to them before they approve. (min 1; max 253) |
{
"client_name": "<client_name>",
"scopes": [],
"key_hash": "<key_hash>",
"key_prefix": "<key_prefix>"
}
Answers
| Status | Body | |
|---|---|---|
| 201 | DeviceAuthorization |
The request is waiting for a person. |
| 400 | ErrorEnvelope |
VALIDATION_ERROR: a body that is not JSON, a field that breaks its rule (named in fields), a bad query value or cursor, or a malformed Idempotency-Key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 409 | ErrorEnvelope |
CONFLICT: the request clashes with the object's current state (the message says how). IDEMPOTENCY_KEY_CONFLICT / IDEMPOTENCY_KEY_IN_FLIGHT: the Idempotency-Key was used with another request, or its first request is still running. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
POST /v1/auth/device/poll
Poll a device sign-in
No scope: any valid key.
Has a person decided yet? Send the device_code from POST /v1/auth/device, no more
often than interval seconds apart.
status is pending while you wait, slow_down if you are asking too fast (wait
interval seconds and carry on), approved once a person has said yes, denied if they
said no, and expired if nobody decided in time. A code that was never issued, or has been
cleared away since, answers expired too, exactly like one that lapsed: the answer never
tells you whether a code existed. Either way, start a new sign-in.
An approval answers with the key's id, its prefix, the permissions it ended up with and when it expires. It never answers with a key: you made it, so you already have it.
It also names the workspace the person chose, by id and name. Apart from GET /workspace
and one route reserved for the BoltClaw MCP server, this is the only answer in the API that
carries a workspace id, and it goes only to the holder of the device code: the program
that started the sign-in, which is about to hold a key for that workspace and could read
the same id with it.
This call needs no API key.
Request body (required)
| Field | Type | |
|---|---|---|
device_code |
string |
(required; min 16; max 200) |
{
"device_code": "<device_code>"
}
Answers
| Status | Body | |
|---|---|---|
| 200 | DeviceAuthorizationStatus |
Where the sign-in has got to. |
| 400 | ErrorEnvelope |
VALIDATION_ERROR: a body that is not JSON, a field that breaks its rule (named in fields), a bad query value or cursor, or a malformed Idempotency-Key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
GET /v1/approvals/{id}
Read an approval you asked for
No scope: any valid key. Another workspace's answers 404.
Has the person decided yet? This is the one thing a key may read about an approval, and
only about its own: an approval another key asked for is 404, exactly like one that
never existed.
You get the status and the deadline, not the summary: the summary was written for the
person who decides, and you already know what you asked for. A pending or approved
ticket past its deadline reads as expired.
Cheap and safe to poll while you wait, and left out of the agent call log so that waiting does not bury the calls that did something. Needs no scope.
Parameters
| Name | In | Type | |
|---|---|---|---|
id |
path | uuid |
An id this API gave you. Anything that is not one of yours is 404. (required) |
Answers
| Status | Body | |
|---|---|---|
| 200 | ApprovalStatus |
The approval, as it stands. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 404 | ErrorEnvelope |
NOT_FOUND: no such object, or it belongs to another workspace. The two are deliberately the same answer and never 403. If the id is right, check you are using the right key. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
POST /v1/auth/key/extend
Extend the key you are using
No scope: any valid key. Accepts Idempotency-Key.
A key approved for an AI assistant lasts 90 days. Within 30 days of its expiry it can push that out by another 90, up to a year from the day it was issued, and then a person signs in again.
Nothing else can be extended this way: a key a person created in the dashboard has an expiry they chose, and this call will not second-guess it. The extension also stops if the person who approved the connection can no longer approve it, or if the organisation has turned AI assistant access off, which is what makes it safe to let a credential renew itself.
Acts only on the key that made the call, so it needs no scope. Safe to call on a schedule:
outside the 30-day window it answers extended: false and changes nothing.
Answers
| Status | Body | |
|---|---|---|
| 200 | KeyExtendResult |
Whether it moved, and when it now expires. |
| 400 | ErrorEnvelope |
VALIDATION_ERROR: a body that is not JSON, a field that breaks its rule (named in fields), a bad query value or cursor, or a malformed Idempotency-Key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 409 | ErrorEnvelope |
CONFLICT: the request clashes with the object's current state (the message says how). IDEMPOTENCY_KEY_CONFLICT / IDEMPOTENCY_KEY_IN_FLIGHT: the Idempotency-Key was used with another request, or its first request is still running. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
POST /v1/auth/key/revoke
Revoke the key you are using
No scope: any valid key. Accepts Idempotency-Key.
Sign out, for real. Deleting a key from a configuration file leaves it working; this ends it. Use it when a person disconnects your program, and when you are uninstalling.
Acts only on the key that made the call, so it needs no scope, and it works even when the organisation has turned AI assistant access off: handing a credential back must never be the thing you cannot do. It cannot be undone, and it is safe to repeat.
If the key is the root of a connection that spans several workspaces, every key in that connection ends with it.
Answers
| Status | Body | |
|---|---|---|
| 200 | KeyRevokeResult |
The key is revoked. |
| 400 | ErrorEnvelope |
VALIDATION_ERROR: a body that is not JSON, a field that breaks its rule (named in fields), a bad query value or cursor, or a malformed Idempotency-Key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
POST /v1/auth/key/revoke-oauth
End a connection
No scope: any valid key.
Ends a whole AI connection, from its root, so no workspace is left reachable. Reserved
for the BoltClaw MCP server; anything else is 404.
It takes a key ID rather than a key, because the MCP server reaches it exactly when it no longer holds one: a person signing the assistant out of their client revokes the grant whose encrypted store was the only copy of the key. The answer is the same for a key id that was a connection's root and for one that was never anything, so it tells a caller nothing about which ids exist.
This call needs no API key.
Request body (required)
| Field | Type | |
|---|---|---|
key_id |
uuid |
The id of any key in the connection. Its root, and every sibling, end with it. (required) |
{
"key_id": "3f8c1e42-9b7a-4d61-a0f5-2c9e1b7d4a83"
}
Answers
| Status | Body | |
|---|---|---|
| 200 | KeyRevokeResult |
The connection is revoked. |
| 400 | ErrorEnvelope |
VALIDATION_ERROR: a body that is not JSON, a field that breaks its rule (named in fields), a bad query value or cursor, or a malformed Idempotency-Key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 404 | ErrorEnvelope |
NOT_FOUND: no such object, or it belongs to another workspace. The two are deliberately the same answer and never 403. If the id is right, check you are using the right key. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
GET /v1/auth/key/workspaces
List a connection's workspaces
No scope: any valid key.
Which workspaces this connection reaches today. Re-resolved on every call against the live
permissions of the person who approved it, so a workspace they can no longer reach drops
out with nothing to revoke. Reserved for the BoltClaw MCP server; anything else is 404.
Answers
| Status | Body | |
|---|---|---|
| 200 | ConnectionWorkspaceList |
The workspaces, and which already have a key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 404 | ErrorEnvelope |
NOT_FOUND: no such object, or it belongs to another workspace. The two are deliberately the same answer and never 403. If the id is right, check you are using the right key. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
POST /v1/auth/key/workspaces
Register a connection's workspace
No scope: any valid key. Accepts Idempotency-Key.
Registers the key for one workspace of a connection, from a hash the caller derived and a
prefix to display. Creates nothing if that workspace already has a live key, and answers
the one it has. Reserved for the BoltClaw MCP server; anything else is 404.
Request body (required)
| Field | Type | |
|---|---|---|
workspace_id |
uuid |
(required) |
key_hash |
string |
(required) |
key_prefix |
string |
(required) |
{
"workspace_id": "3f8c1e42-9b7a-4d61-a0f5-2c9e1b7d4a83",
"key_hash": "<key_hash>",
"key_prefix": "<key_prefix>"
}
Answers
| Status | Body | |
|---|---|---|
| 200 | ConnectionWorkspaceKey |
That workspace already had a key. |
| 201 | ConnectionWorkspaceKey |
Registered. |
| 400 | ErrorEnvelope |
VALIDATION_ERROR: a body that is not JSON, a field that breaks its rule (named in fields), a bad query value or cursor, or a malformed Idempotency-Key. |
| 401 | ErrorEnvelope |
UNAUTHORIZED: no key, or one that is malformed, unknown or revoked. It never says which. |
| 403 | ErrorEnvelope |
INSUFFICIENT_SCOPE: the key lacks this operation's scope. Or ORGANISATION_SUSPENDED: the key's organisation is suspended. Never about another workspace's object, which is 404. |
| 404 | ErrorEnvelope |
NOT_FOUND: no such object, or it belongs to another workspace. The two are deliberately the same answer and never 403. If the id is right, check you are using the right key. |
| 429 | ErrorEnvelope |
RATE_LIMITED: too many requests. Wait for Retry-After seconds. |
| 500 | ErrorEnvelope |
INTERNAL_ERROR: ours. Safe to retry; send the same Idempotency-Key on a POST. |
Shapes
The objects these operations send and answer.
ApprovalAction
What an assistant asked to do. The actions in the first group are the ones an organisation may decide to stop being asked about, or waive for one connection for a few hours; the rest are always asked, because they move somebody else's money or change somebody else's access.
One of: post.publish, post.delete, inbox.reply, inbox.hide, conversation.reply, automation.enable, automation.delete, page.delete, page.unpublish, link.delete, lead.delete, referral.payout.paid, referral.commission.adjust, referral.partner.approve, social.account.disconnect, referral.commission.bonus, referral.reward.delete, referral.group.delete, referral.referrer.erase, referral.grant.fulfil, referral.grant.fail, referral.stripe.codes, referral.testdata.clear, referral.flag.dismiss, referral.flag.confirm, referral.risk.update, referral.payout.send, referral.payout.settings, referral.commission.forfeit, referral.tax.settings, referral.brand.update, referral.domain.add, referral.domain.remove, referral.listing.update, referral.library.delete, referral.broadcast.send, referral.import.commit, referral.contest.award, referral.contest.cancel, referral.waitlist.disqualify, referral.waitlist.invite, referral.tier.update, referral.waitlist.end, referral.waitlist.forget, referral.shopify.codes, referral.terms.update, referral.subject.erase, referral.program.archive, referral.partner.ban, referral.partner.unban, referral.commission.approve, referral.code.create, referral.link.archive, referral.program.restore, referral.signup.rotate, referral.waitlist.rotate, referral.embed.rotate, referral.referrer.approve, referral.code.link, referral.payout.reopen.
ApprovalStatus
| Field | Type | |
|---|---|---|
id |
uuid |
(required) |
action |
ApprovalAction |
What an assistant asked to do. The actions in the first group are the ones an organisation may decide to stop being asked about, or waive for one connection for a few hours; the rest are always asked, because they move somebody else's money or change somebody else's access. (required; one of post.publish, post.delete, inbox.reply, inbox.hide, conversation.reply, automation.enable, automation.delete, page.delete, page.unpublish, link.delete, lead.delete, referral.payout.paid, referral.commission.adjust, referral.partner.approve, social.account.disconnect, referral.commission.bonus, referral.reward.delete, referral.group.delete, referral.referrer.erase, referral.grant.fulfil, referral.grant.fail, referral.stripe.codes, referral.testdata.clear, referral.flag.dismiss, referral.flag.confirm, referral.risk.update, referral.payout.send, referral.payout.settings, referral.commission.forfeit, referral.tax.settings, referral.brand.update, referral.domain.add, referral.domain.remove, referral.listing.update, referral.library.delete, referral.broadcast.send, referral.import.commit, referral.contest.award, referral.contest.cancel, referral.waitlist.disqualify, referral.waitlist.invite, referral.tier.update, referral.waitlist.end, referral.waitlist.forget, referral.shopify.codes, referral.terms.update, referral.subject.erase, referral.program.archive, referral.partner.ban, referral.partner.unban, referral.commission.approve, referral.code.create, referral.link.archive, referral.program.restore, referral.signup.rotate, referral.waitlist.rotate, referral.embed.rotate, referral.referrer.approve, referral.code.link, referral.payout.reopen) |
status |
string |
(required; one of pending, approved, denied, used, expired) |
expires_at |
date-time | null |
(required) |
decided_at |
date-time | null |
(required) |
ConnectionRevoke
| Field | Type | |
|---|---|---|
key_id |
uuid |
The id of any key in the connection. Its root, and every sibling, end with it. (required) |
ConnectionWorkspaceKey
| Field | Type | |
|---|---|---|
key_id |
uuid |
(required) |
created |
boolean |
False when that workspace already had a live key. (required) |
scopes |
Scope[] |
(required) |
ConnectionWorkspaceList
Answered only to the BoltClaw MCP server, which keeps one key per workspace of a connection
and needs each workspace's id to do it. Anything else asking is answered 404.
| Field | Type | |
|---|---|---|
connection_id |
uuid |
(required) |
all_workspaces |
boolean |
The connection follows the organisation, including workspaces made after it was approved. (required) |
data |
object[] |
(required) |
next_cursor |
NextCursor |
Pass back as cursor for the next page; null on the last page. (required) |
ConnectionWorkspaceRegister
| Field | Type | |
|---|---|---|
workspace_id |
uuid |
(required) |
key_hash |
string |
(required) |
key_prefix |
string |
(required) |
DeviceAuthorization
| Field | Type | |
|---|---|---|
device_code |
string |
Your half of the exchange. Keep it, poll with it, and never show it to anybody. (required) |
user_code |
string |
What the person types, as XXXX-XXXX. Show it to them. (required) |
verification_uri |
uri |
(required) |
verification_uri_complete |
uri |
The same page with the code filled in. Use it when you can show a link or a QR code. (required) |
expires_in |
integer |
Seconds until the request lapses. (required) |
expires_at |
date-time | null |
(required) |
interval |
integer |
Seconds to wait between polls. Asking faster is answered slow_down. (required) |
DeviceAuthorizationPoll
| Field | Type | |
|---|---|---|
device_code |
string |
(required; min 16; max 200) |
DeviceAuthorizationStart
The key is made on your machine and never sent. key_hash is the SHA-256 of the whole
bc_live_... string, as 64 lowercase hex characters; key_prefix is the first 8
characters of the random body after the prefix, and is what a person sees in the list of
connections.
| Field | Type | |
|---|---|---|
client_name |
string |
What you are called, shown to the person deciding. Never trusted for anything. (required; min 1; max 80) |
client_host |
string |
The machine you are running on, shown beside the name so a person can tell two terminals apart. (min 1; max 120) |
scopes |
Scope[] |
The permissions you are asking for. Ask for what you need and no more. (required; <= 25 items; >= 1 items) |
key_hash |
string |
(required) |
key_prefix |
string |
(required) |
flow |
string |
device for a program somebody is sitting at. oauth is the hosted BoltClaw MCP server acting for a person, and only it may ask for one. (default device; one of device, oauth) |
redirect_host |
string |
Only with flow: oauth. The host the person will be sent back to, shown to them before they approve. (min 1; max 253) |
DeviceAuthorizationStatus
pending while you wait, slow_down if you are asking too fast, approved once a person
has said yes, denied if they said no, expired if nobody decided in time. A code that
was never issued answers expired as well, so the answer never says whether one existed.
| Field | Type | |
|---|---|---|
status |
string |
(required; one of pending, slow_down, approved, denied, expired) |
interval |
integer |
Only with slow_down. Wait this many seconds. |
key |
object |
Only with approved. Never the key itself, which you already hold. |
workspace |
object |
Only with approved. The workspace the person chose. One of the few answers that carries a workspace id, because it goes only to the holder of the device code: the program that started the sign-in, whose new key belongs to this workspace. |
callback_nonce_hash |
string |
Only for the oauth flow, and only to the client that started it. |
KeyExtendResult
| Field | Type | |
|---|---|---|
extended |
boolean |
False when it was not yet near enough to its expiry, or is already at its limit. (required) |
expires_at |
date-time | null |
(required) |
reason |
string |
Why it did not move, when it did not. |
KeyRevokeResult
| Field | Type | |
|---|---|---|
revoked |
true |
(required) |
NextCursor
Pass back as cursor for the next page; null on the last page.
string | null.