@proof-holdings/mcp-server
OfficialAllows connecting a Cloudflare account so DNS records are written automatically for domain verification.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@proof-holdings/mcp-serverCreate a verification for my phone number and wait for the result."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@proof-holdings/mcp-server
MCP (Model Context Protocol) server for the proof.holdings API. Exposes 179 tools for AI agents to create verifications, validate proofs, manage assets, and more.
Two ways to connect
Hosted — nothing to install. The same tools are served over HTTP at
https://api.proof.holdings/mcp. Any MCP client or agent framework with HTTP transport can
connect — add the URL as a remote MCP server in its settings (the config key varies by client).
Authentication happens in the browser the first time a tool needs an account. As a config fragment:
{ "mcpServers": { "proof": { "type": "http", "url": "https://api.proof.holdings/mcp" } } }⚠️ Versions before 1.1.0 predate the delegation tools and the keyless public mode and expose
an older, smaller surface than this README describes. If a client is pinned to 1.0.0, upgrade it
or use the hosted server above. The current instructions are always at
https://proof.holdings/md/docs/mcp.md.
Local — this package. Installs and runs as a stdio server:
npm install -g @proof-holdings/mcp-serverOr run directly with npx (no install needed):
npx @proof-holdings/mcp-serverRelated MCP server: vtimestamp-mcp
Configuration
Variable | Required | Default | Description |
| No | — | API key ( |
| No |
| API base URL |
Get your API key from the proof.holdings dashboard, or let the
server get one for you with login (below).
Sign in from a terminal
npx @proof-holdings/mcp-server loginPick how to log in — Telegram, WhatsApp, SMS or email (
--channel, or asked). The terminal shows the link and a QR code to scan with your phone, the text and number to send for SMS, or asks for the code from the email.Creating an API key needs one more confirmation, preferably on a different channel; it also runs in the terminal.
The new key is saved in
~/.proof-holdings/credentials(readable by you only), under the API inPROOF_BASE_URL. The server uses it from its next start, so restart your MCP client's server.The sign-in session the terminal used is then signed out. If that fails,
loginsays so; sign it out in the dashboard under Settings → Security → Signed-in devices.
PROOF_API_KEY, when set, always wins over the saved key, and a key saved for one API (say, staging) is
never sent to another. Then leave env out of the client config:
{ "mcpServers": { "proof-holdings": { "command": "npx", "args": ["-y", "@proof-holdings/mcp-server"] } } }Command | What it does |
| Signs in, confirms, creates and saves a key. |
| Shows which key the server would start with and where it comes from. No network call. |
| Removes the saved key for this API from this computer. |
The key does not expire. Logging in again replaces the saved key but does not revoke the old one, and
logout only forgets it locally: revoke keys you no longer use in the dashboard (API keys) or with the
revoke_api_key tool. login needs an interactive terminal and an https:// API (plain http only for
localhost).
Client Setup
Add the following to your MCP client config file:
{
"mcpServers": {
"proof-holdings": {
"command": "npx",
"args": ["-y", "@proof-holdings/mcp-server"],
"env": {
"PROOF_API_KEY": "pk_live_your_key_here"
}
}
}
}Config file location by client:
Client | Config file |
Claude Desktop (macOS) |
|
Claude Desktop (Windows) |
|
Cursor |
|
Claude Code | Run |
Windsurf |
|
Keep the scoped npx -y @proof-holdings/mcp-server command even after a global install. A bare command
name is looked up on PATH, or by npx in the npm registry, where it can belong to someone else's package.
Tools (179 tools)
Group totals are exact. The tables name the tools you are most likely to reach for rather than all
of them — your MCP client's own tools/list is the complete, current list, and it is the one this
server answers from.
Verifications & requests (28 tools)
Tool | Description |
| Create a verification challenge |
| Get verification status |
| Submit a verification code |
| Trigger a verification check |
| Poll until it completes |
| One phone, up to three channels, first completion wins |
| Create a multi-asset request |
| Look a request up by reference id |
Domains & DNS (23 tools)
Tool | Description |
| Add a domain to verify |
| Check the challenge record and mint the proof |
| Connect Cloudflare so records are written for you |
| Prove control using stored credentials |
| Set up sending from the domain |
Account, settings & billing (39 tools)
Tool | Description |
| One-call snapshot of the account |
| Quota and usage for the period |
| The prepaid balance and the auto top-up setting |
| Search across the account |
| Bootstrap a new account (no key needed) |
| Create a scoped API key |
| List verified assets and their proof handles |
HITL approvals & consent (22 tools)
Tool | Description |
| Create a human-approval configuration |
| Send an approval request to a person |
| Poll until a person approves or denies |
| Ask a person to consent to being contacted |
| Withdraw a consent |
Circles & Proof of Me (15 tools)
Tool | Description |
| Create a circle of trusted contacts |
| Add a contact |
| Send a single-use enrollment link |
| Run a cross-channel identity check |
Public profiles (12 tools)
Tool | Description |
| Create a public profile |
| Claim a public username |
| Choose which proofs a profile shows |
Templates & webhooks (11 tools)
Tool | Description |
| List a sub-account's message templates |
| Render a template with variables |
| List webhook deliveries |
| Retry a failed delivery |
Webhook endpoints (7 tools)
Each endpoint has its own URL, events and signing secret, and serves either every sub-account or the ones you select. A signing secret is returned only on create and on rotate — store it then.
Tool | Description |
| List the account's webhook endpoints |
| Get one endpoint (no secret) |
| Add an endpoint; returns its signing secret |
| Change URL, events, scope, sub-accounts or status |
| Delete an endpoint |
| Replace an endpoint's signing secret |
| Replace a sub-account's callback signing secret |
Delegations & proofs (13 tools)
Tool | Description |
| Authorize an artifact from a domain you have proven |
| Revoke a delegation |
| Check whether an artifact is authorized by the domain it claims |
| Verify a signed proof token (no key needed) |
| Read a proof's status by its public handle |
| Read the revocation list (no key needed) |
| Fetch the current (re-signed) token of a proof you own (not one of your own verified assets: that is read in the dashboard) |
| List your proofs re-signed since an instant, except those of your own verified assets |
| Fetch an active delegation's current token by handle (no key needed) |
Sign-in & sessions (9 tools)
Tool | Description |
| Begin a sign-in (no key needed) |
| Poll until sign-in completes |
| Who the current session belongs to |
| Render a sign-in link for the user to open |
Test Mode
Use a test-mode API key (pk_test_*) to interact with the API without creating real verifications. Test-mode keys are available in your dashboard.
Transport
Two transports ship in this package:
stdio (default, what
npx -y @proof-holdings/mcp-serverstarts) — the server communicates over stdin/stdout. One user per process; this is what a client launches locally.Streamable HTTP (
node dist/remote.js) — a remote server that many users connect to over the network by URL, with no install. A connection starts ANONYMOUS — the keyless surface (account bootstrap, login, proof and delegation verification) works with no credential at all — and a tool that needs an account answers401with aWWW-Authenticatechallenge naming the authorization server, which is what a standards-compliant client follows to sign in. The 401 lands on the TOOL CALL and never on a bareinitializeortools/listFOR AN ANONYMOUS CONNECTION: measured against live clients, refusing an anonymous handshake reads to the user as a connection timeout rather than as an invitation to log in. Three shapes are refused at the handshake instead — a presented token that does not resolve (there the 401 is what makes a client refresh), a request whose credential does not match the session it names, and an opening batch that smuggles a keyed tool call alongsideinitialize. A signed-in client sends the API key it was granted in theAuthorizationheader — the only place a credential is read, never a query parameter — and each connection gets its own server and HTTP client, so one user's key or session can never reach another./mcpservesPOST(every JSON-RPC message) andDELETE(ending a session); every other method — including the optional standaloneGETevent stream — answers405withAllow: POST, DELETE, whatever session or credential the request carries. Nothing on this server pushes notifications, so declining the stream costs a client nothing, and it is what lets a client on Node 26's built-infetchwork: over HTTP/2 to the edge, with that stream open, it never sent its next request.PORT(default 3100),MCP_MAX_SESSIONS(default 100),MCP_SESSION_TTL_MS(default 30 min, counted from the last POST the server ACCEPTED — one it answered below 400. A POST refused before any work happens does not postpone it, whether the refusal is ours (body over 4MB) or the transport's (unparseable or empty body, unsupportedmcp-protocol-version, a secondinitialize), and neither does a refused method. The official client does not recover from a sweep on its own: measured against SDK 1.27.1 — while the event stream was still offered, so not re-measured since — the next tool call fails withunknown_sessionuntil the host reconnects the server. Size the TTL with that in mind — it is a memory bound paid for in reconnects, not a transparent one);/healthzreports the live session count.
Delegation (_meta)
The server card (server.json) can carry a Proof of Delegation publication under the
namespaced _meta key holdings.proof/delegation:
{
"_meta": {
"holdings.proof/delegation": { "token": "<delegation JWT>" }
}
}The token is an ES256 JWT minted by proof.holdings attesting exactly
one thing: the controller of the principal domain authorized the delegate artifact. It is
not a statement that the server is safe, audited, or endorsed. A verifier checks the signature
against the issuer JWKS, then compares principal and delegate to facts it resolved itself —
a token copied into another package fails that comparison, because its delegate names the
genuine artifact. Details: Delegations — API reference.
A card published through the official MCP registry must carry the entry under
_meta["io.modelcontextprotocol.registry/publisher-provided"] (the registry drops every other
_meta key), so readers check both locations. This package's own card carries only the top-level
key, so its registry entry carries no delegation; the website card
https://proof.holdings/.well-known/mcp/server-card.json does.
Maintainers: the entry is written by the fail-closed publish tool, never by hand — from the
repository root, after the delegation is minted for pkg:npm/@proof-holdings/mcp-server:
npm run delegation:publish -- --target mcp --token <jwt>
# or mint + publish in one step (needs PROOF_API_KEY):
npm run delegation:publish -- --target mcp --mint --control-proof ph_ctl_<32hex>The tool refuses any token whose claims do not name this exact package with
principal: proof.holdings (the same check --target a2a performs against the A2A agent
card's own url before regenerating /.well-known/agent-card.json). Besides server.json,
--target mcp writes the website card's source (web/src/lib/geo/mcp-delegation-publication.json)
and regenerates /.well-known/mcp/server-card.json and /.well-known/mcp.json, so it needs
web/node_modules installed. For either target, if the card-regeneration step fails after the
source file is written, just re-run the command — the token is already validated and the
regeneration is idempotent. The website cards reach readers only with the next website deploy.
Verifying someone else's delegation (verify_delegation)
This server also checks delegations, not just publishes one. The verify_delegation tool
runs the reference verifier (@proof-holdings/delegation-verifier)
over another server's card and needs no API key — verification runs against public surfaces
only.
{
"card": { /* the MCP server.json or A2A agent card you fetched */ },
"delegate": { "type": "purl", "value": "pkg:npm/postmark-mcp" },
"expected_principal": "postmarkapp.com"
}Both pins are required, and they close different attacks:
delegatemust be the artifact identity you resolved — the package you are about to install, the endpoint you are about to call. Never copy it out of the card being checked: a published token is a bearer artifact, so comparing it against a field of the same card would bless a token pasted in from somewhere else.expected_principalis the domain you expect to stand behind it. An issuer binds the artifact to nothing, so any domain owner can mint a genuine, signature-valid delegation naming someone else's package. Without this pin a verdict would only mean "some domain claims this".
Re-checking everything you already trust (verify_delegations)
verify_delegation answers "is this one good, right now, because you asked". If an agent has
already resolved and verified thirty-five artifacts, re-verifying them one call at a time does
not scale — verify_delegations batch-checks up to 50 in a single call, also with no API key.
{
"items": [
{ "card": { /* ... */ }, "delegate": { "type": "purl", "value": "pkg:npm/postmark-mcp" }, "expected_principal": "postmarkapp.com" },
{ "token": "<jwt>", "delegate": { "type": "url", "value": "https://example.com/mcp" }, "expected_principal": "example.com" }
]
}Each item takes exactly the shape verify_delegation requires (card XOR token, delegate,
expected_principal) and is verified independently — no
cross-item state, nothing persisted, and one item failing never affects another item's result.
Revocation is always checked (there is no check_status: false on this tool — the entire point
of a batch re-check is to see what changed).
Two things this tool deliberately does NOT do:
It does not discover what you have installed. You must already hold each artifact's
cardortoken. It has no DNS-pointer resolution and fetches no caller-supplied URL — the same trust boundaryverify_delegationalready draws, kept narrow on purpose (seesrc/services/delegationPointer/resolve.ts's documented gaps in the main repository, which this tool stays outside of).It does not run continuously. Each call is a single point-in-time check. There is no cadence, no scheduler, no push notification — call it again whenever you want a fresh answer.
Each result in results[] carries an outcome, one of four buckets:
Outcome | Meaning |
| The delegation verified — same meaning as |
| A genuine negative verdict: revoked, suspended, expired, a mismatched principal or delegate, a token of schema 1.x ( |
| The artifact publishes no delegation at all. An absence, never an accusation. |
| We could not reach the issuer or otherwise get a confident answer right now (e.g. its JWKS or status endpoint is unreachable). Never treat this as a bad verdict — it means "ask again later", not "revoked". |
A result also carries checked_at — the ISO timestamp of the moment that item's own check
completed, not one timestamp shared across the whole call — so "established locally" is never
presented as "established by reaching us, at this moment" without saying which.
⚠️ Release order (maintainers)
package.json declares @proof-holdings/delegation-verifier as a runtime dependency, so the
range it names has to be resolvable on the registry before this package is uploaded:
@proof-holdings/delegation-verifier is published BEFORE @proof-holdings/mcp-server, on every
release that moves the range. This server is launched via npx by every documented client, so a
release whose dependency the registry cannot resolve makes npx @proof-holdings/mcp-server fail
with E404 for everyone until the verifier lands. A run of
.github/workflows/publish-packages.yml with target: all enforces the order by its step order;
a publish by hand from a terminal has nothing enforcing it but docs/runbooks/npm-release.md.
Working on the verifier and the server together does not need a publish. Link the sibling instead:
npm run verifier:link # cd mcp && npm install ../packages/delegation-verifier --no-saveIn this repository the test suite needs no link at all: it resolves the verifier's SOURCE through a
vitest alias rather than node_modules, so it is green on a fresh clone and picks up an uncommitted
verifier change without a build. The alias is keyed on the sibling verifier package being present;
in the public mirror, which holds this package alone, the suite runs against the verifier npm ci
installs.
Requirements
Node.js >= 18.0.0
A proof.holdings API key for the keyed tools. The server starts and answers the keyless ones without it — see Configuration above.
Links
proof.holdings — Product website
API Documentation — REST API reference
Dashboard — Manage your account and API keys
License
Available Tools
179 toolsadd_circle_memberAInspect
Add a pending member to a Circle by name, with an optional pre-declared WhatsApp phone. The Telegram chat id is captured later when the member taps the enrollment deep link.
Agent usage: after adding a member, call invite_circle_member to mint the single-use enrollment link the member taps to bind their messenger identity.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID to add the member to | |
| name | Yes | Display name of the member | |
| whatsapp_phone | No | E.164 WhatsApp phone with a leading + (optional, declared) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| name | No | |
| status | No | |
| enrolled_at | No | |
| has_telegram | No | Whether the member has a Telegram channel (declared or verified) |
| has_whatsapp | No | Whether the member has a WhatsApp channel (declared or verified) |
| mesh_opt_out | No | The member sent /opt_out: they receive no drills, reminders or checks they did not start themselves |
| mesh_opted_in | No | |
| last_verified_at | No | When this member last CONFIRMED an identity check asked of them — i.e. last proved it was them. Null until they have. |
| enrolled_phone_hint | No | Masked form of the phone the contact proved when they enrolled (the Telegram shared contact or the WhatsApp sender) — country prefix and last four digits only, never the full number. Lets the owner see who actually joined. Null until the member enrolls, and for members enrolled before it was recorded. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description adds the meaningful state model (member starts pending, Telegram chat id is bound later via the enrollment deep link) and the auth gate. It does not mention rate limits, duplicate-name behavior, or whether the WhatsApp phone must match at enrollment time, leaving a few behavioral questions open.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then workflow, then access, which is the right order for an agent. There is mild redundancy between 'the Telegram chat id is captured later when the member taps the enrollment deep link' and the 'mint the single-use enrollment link the member taps to bind their messenger identity' sentence in the usage note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter mutation with an output schema already present, the description covers the full lifecycle: prerequisite auth, what state the member lands in, and the required follow-up call. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds meaning by framing name as the sole identity signal and the phone as 'pre-declared' rather than verified, and by situating the chat id as a later-bound value not passed here. It stops short of explaining format edge cases (e.g., name collisions), which the schema handles only via min/max length.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Add a pending member to a Circle') plus the key scoping detail that the member is pending and identified by name, with an optional pre-declared WhatsApp phone. This clearly separates it from sibling tools like invite_circle_member (mints the link), add_circle_member_channel (binds a channel), and create_circle_member_drill (test flow).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit sequencing rule ('after adding a member, call invite_circle_member to mint the single-use enrollment link') and a negative case ('start_login does NOT open this tool'), which prevents a plausible wrong path. Prerequisites (Proof account + PROOF_API_KEY) are spelled out with the remedy.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_circle_member_channelAInspect
Declare a channel for a Circle member. Returns 409 if that channel type already exists on the member. The identifier is a Telegram chat id or an E.164 WhatsApp phone (per-channel format validated server-side).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| channel | Yes | Channel type (telegram or whatsapp) | |
| member_id | Yes | Member ID to add the channel to | |
| identifier | Yes | Telegram chat id, or E.164 WhatsApp phone with a leading + |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| status | No | |
| channel | No | |
| created_at | No | |
| verified_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare non-read-only and non-destructive, which is thin; the description adds real context: the 409 conflict when the channel type already exists, and that identifier format is validated server-side rather than client-side. It does not say whether the call is idempotent or what permissions beyond a Proof account are required, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The functional sentence and the 409/format caveat are front-loaded, and the ACCESS block is clearly separated. The auth paragraph is slightly verbose for an environment variable that is documented elsewhere, but the 'start_login does NOT open this tool' line earns its place by preventing a common dead end.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description covers the mutation, the duplicate-error case, identifier validation, and the auth gate. The main remaining gap is the interaction with sibling member tools (e.g. whether the member must already exist), which is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with every parameter documented including the channel enum and the leading-'+' E.164 requirement. The description restates the identifier-format rule but adds no new syntax or constraints beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Declare a channel for a Circle member.' Combined with the channel enum (telegram/whatsapp) referenced later, an agent can distinguish this from list_circle_member_channels and remove_circle_member_channel without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a hard prerequisite (Proof account, PROOF_API_KEY set, server restart) and explicitly warns that start_login does not unlock this tool, which is genuinely useful routing info. However, it never states when to use this versus add_circle_member, invite_circle_member, or the discovery tools that produce a Telegram chat id, so the alternative selection is left implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_domainAInspect
Add a new domain to verify ownership. Optionally specify email sending intent and verification method.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name to add (e.g. example.com) | |
| profile_id | No | The sub-account (24 hex characters) whose email settings this domain is for | |
| for_email_sending | No | Whether this domain is for email sending | |
| verification_method | No | Preferred verification method |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations only tell the agent this is a non-read-only, non-destructive mutation; the description adds the auth/session prerequisite and the fact that the domain is being registered for a later ownership check. It does not disclose idempotency behavior, whether a DNS record is created immediately, or what happens on duplicate domains.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks: the purpose sentence first, then access prerequisites. The ACCESS block is slightly verbose given it restates the restart requirement, but nothing is wasted and the key action is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the auth prerequisite is covered. Remaining gaps are modest: the description doesn't say what the natural next step is (verification) or how this differs from the DNS-provider connection siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each of the four parameters already has a description, so the baseline is 3. The prose names the two optional concepts (email sending intent, verification method) but adds no meaning beyond the schema — notably nothing about profile_id or how verification_method interacts with the account's DNS provider.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — 'Add a new domain to verify ownership' — plus the optional knobs (email sending intent, verification method). It implicitly separates itself from follow-up siblings like verify_domain or start_domain_verification, but never names an alternative such as connect_cloudflare or connect_dns_provider, which is arguably the closest decision point.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS paragraph gives a real prerequisite workflow: a Proof account, PROOF_API_KEY, or signing in via start_login before retrying. That is genuine when-to-use context. However there is no guidance on when to pick this over automated DNS-connection tools, or on what to do if the domain already exists.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_verification_providerADestructiveInspect
Add an additional DNS provider for verification to an already-verified domain. Note: credentials will be visible in the AI conversation context.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| provider | Yes | DNS provider identifier | |
| credentials | Yes | Provider-specific credential key-value pairs |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag the mutation as destructive, and the description meaningfully adds that the supplied credentials will be exposed in the conversation context — a non-obvious side effect an agent must surface to the user. It also documents the auth path (PROOF_API_KEY or start_login). It stops short of saying what happens to existing providers on the domain or whether the new provider replaces anything.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and precondition are front-loaded in the first sentence, and the exposure warning follows immediately. The ACCESS paragraph is slightly verbose with restart instructions, but each sentence is actionable rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations, a full-coverage schema and an output schema already present, the description only needs to cover preconditions, auth and side effects — which it does. The remaining gap is sibling disambiguation among the many DNS/credential tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns an extra point by clarifying that the credentials object is passed inline and becomes visible in context, which affects how the value should be handled. It adds nothing about the 'provider' identifier domain (e.g. valid provider strings), but the schema already carries that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (add a DNS provider for verification) plus a meaningful precondition that the domain must already be verified. However, it never distinguishes itself from close siblings such as connect_dns_provider or create_dns_credential, so an agent still has to guess which of the DNS-credential tools is correct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'already-verified domain' constraint is genuine when-to-use guidance, and the ACCESS paragraph explains how to become authorized. But there is no when-not guidance and no comparison to the several closely overlapping DNS credential tools in the sibling list, which is the main selection risk here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancel_user_requestADestructiveInspect
Cancel a pending verification request. Only the creator can cancel.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification request ID to cancel |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the mutation profile is known; the description adds real context on top — creator-only authorization, pending-only eligibility, and the API-key/login prerequisite. It stops short of saying whether a cancelled request can be revived or re-created, which matters for a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, action first, access second; nothing is padded. The phrasing 'a session opens this tool' is slightly awkward but the instruction sequence (set key or start_login, then retry) is still readable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and the auth flow plus eligibility rules are covered. The remaining gap is sibling disambiguation against cancel_verification_request, which an agent must resolve before calling this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'id' parameter is documented as 'Verification request ID to cancel'. The description adds no format, prefix, or lookup guidance beyond that, so the schema does all the work — the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Cancel a pending verification request') plus an authorization scope ('Only the creator can cancel'). It does not, however, distinguish itself from the near-identically named sibling cancel_verification_request, leaving the agent to guess which cancel tool applies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete preconditions for use: the request must be pending and the caller must be its creator. The ACCESS paragraph further explains how to become authenticated before retrying. What is missing is any guidance on when to choose this over cancel_verification_request, the obvious alternative in the sibling list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancel_verification_requestADestructiveInspect
Cancel a pending verification request. Only pending requests can be cancelled.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification request ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| status | Yes | |
| message | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, so the safety profile is covered. The description adds real context beyond that: the state constraint that only pending requests qualify, plus an explicit authentication prerequisite (PROOF_API_KEY + restart) and a note that start_login does not grant access. It stops short of saying whether the cancellation is reversible or what happens to proof data.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and its precondition are front-loaded in two tight sentences; the access block follows and is clearly separated. The access note is slightly verbose but earns its place as an operational prerequisite.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and annotations carry the destructive profile. The description fills the remaining gaps an agent needs: the pending-only precondition and the API-key requirement.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single 'id' parameter already documented as the verification request ID. The description adds no further meaning about the identifier, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Cancel a pending verification request') and adds a scope qualification. An agent can identify the operation immediately, though it does not explicitly distinguish itself from the nearby cancel_user_request sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides one concrete precondition ('Only pending requests can be cancelled'), which tells the agent when the call will succeed. It does not name alternatives for non-pending requests or state what the caller should do instead, leaving the routing guidance incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_domain_credentialsARead-onlyInspect
Check if stored DNS credentials have access to a domain. Use before triggering verification to confirm the credentials work.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID to check credentials for |
Output Schema
| Name | Required | Description |
|---|---|---|
| suggestion | No | Sent when no credential can reach the domain. |
| has_credentials | Yes | Whether the account holds any valid DNS credential. When false, only `accessible_credentials` (empty), `detected_provider` and `suggestion` are sent. |
| detected_provider | Yes | |
| registrar_provider | No | |
| accessible_credentials | Yes | |
| has_accessible_credential | No | |
| has_registrar_credentials | No | |
| can_try_ownership_verification | No | A registrar credential can confirm ownership while the zone is served elsewhere. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already establishes the safety profile, and the description adds information the annotations do not carry: the tool operates on stored credentials and requires a Proof account, configured either via PROOF_API_KEY plus a server restart or via start_login. It does not explain what a negative result looks like (no credentials vs. insufficient permissions), but that is largely the output schema's job.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and sequencing guidance are front-loaded in the first two sentences, and the ACCESS block is clearly separated. The access paragraph is slightly long relative to the tool's simplicity but is genuinely necessary setup information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one parameter, an output schema, and a readOnly annotation, the definition covers the essentials, and the auth/bootstrap instructions are a real addition for a tool that will otherwise fail silently for unauthenticated agents. Only the mapping from a failed check to a next action is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter 'id' is documented there as the domain ID. The description's phrase "a domain" adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb and resource: it checks whether stored DNS credentials have access to a given domain, which distinguishes it from verify_domain_with_credentials and trigger_verification. It stops short of naming the sibling it is not, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use before triggering verification to confirm the credentials work" gives an explicit sequencing condition that ties it to trigger_verification. There is no explicit when-not guidance or named alternative for the case where credentials are absent (e.g., create_dns_credential).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_domain_email_statusARead-onlyInspect
Check the email sending setup status for a domain, including DNS record configuration progress.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses the Proof account requirement, two authentication routes, the need to restart the server after setting the API key, and the need to retry after login. These are meaningful invocation behaviors, although no additional polling or progress-state semantics are provided.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in one clear sentence, followed by a separate, practical ACCESS paragraph. Despite slightly awkward phrasing in "a session opens this tool," the text is compact and each part serves invocation or authentication.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read-only status tool with an output schema, the purpose, DNS-progress scope, and authentication requirements provide enough information to invoke it successfully. Explicit workflow placement and a source for the domain ID would make the definition more complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the sole required id parameter is already documented as a Domain ID, so the baseline is 3. The description adds no information about the ID's format or how to obtain it, such as through list_domains.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb and resource: checking a domain's email sending setup status, with DNS record configuration progress as a useful scope detail. It does not explicitly distinguish this status check from siblings such as setup_domain_email or check_domain_verification.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description establishes the context of monitoring email setup and DNS configuration progress, and it gives concrete guidance for gaining access through PROOF_API_KEY or start_login. It does not explain where this fits in the workflow, such as checking after setup_domain_email, or when a different domain-status tool is preferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_domain_verificationAInspect
Check the status of a pending domain verification. Triggers a DNS/HTTP check and returns the updated status.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain verification ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| domain | No | |
| status | No | |
| verified | No | |
| check_count | No | |
| verified_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations mark this as non-read-only and non-destructive, and the description explains why: it triggers a network DNS/HTTP check as a side effect and returns an updated status rather than cached data. The access paragraph adds credential requirements and a restart step, which the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences deliver purpose and side effect, then a clearly separated access block. Every sentence carries information; only slight redundancy between 'check the status' and 'returns the updated status'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema is present, so return values need no explanation, and the critical operational prerequisite (Proof account, PROOF_API_KEY, server restart) is stated. For a one-parameter tool this is essentially complete; only comparison to sibling verification tools is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'id' parameter is already described as the 'Domain verification ID'. The description reinforces that the ID refers to a pending verification rather than a domain, but adds no syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Check the status') and resource ('pending domain verification') and adds that it triggers a live DNS/HTTP check, which separates it from passive readers like get_verification or get_domain. It does not name a specific sibling as the alternative, so it falls short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'pending domain verification' implies usage scope (only after a verification was started), and the ACCESS paragraph usefully explains the account prerequisite and that start_login will not unlock this tool. However, it never says when to prefer this over verify_domain, trigger_verification, or start_domain_verification, which are close siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_user_domain_verificationAInspect
Trigger a check on the domain verification challenge. Call after placing DNS record or HTTP file.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Domain verification session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| asset | No | The domain asset holding the proof; present when `status` is `verified` |
| status | Yes | |
| message | No | Why the check is still pending; present when `status` is `pending` |
| verified_at | No | Present when `status` is `verified` |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description adds meaningful operational context: it requires a Proof account, can be authenticated via PROOF_API_KEY, and otherwise needs a login session from start_login. It does not fully explain the side effects of 'triggering' a check, but the auth and timing details materially help correct invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the purpose and timing before the access note. Every sentence carries useful information, though the phrase 'a session opens this tool' is slightly awkward and could be clearer.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema and annotations, the description covers the essential purpose, call timing, and authentication prerequisite. The main remaining gap is sibling disambiguation, which is more a usage-guideline issue than missing core context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single session_id parameter, so the schema already documents its meaning as the domain verification session ID. The description does not add parameter-level detail beyond indirectly referring to a session, which is acceptable given the high schema coverage but not enriching.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Trigger a check on the domain verification challenge.' It is clear what the tool does, but it does not distinguish this user-domain check from the similarly named sibling check_domain_verification or from get_user_domain_verification_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete trigger condition: call after placing the DNS record or HTTP file. It also explains the Proof account prerequisite. However, it does not name alternatives or clarify when to use this instead of sibling verification-status or domain-verification tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
claim_usernameAInspect
Claim a unique username for the authenticated user's public profile. Usernames must be 3-30 characters, alphanumeric and underscores only.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| username | Yes | Username to claim (3-30 chars, alphanumeric and underscores) |
Output Schema
| Name | Required | Description |
|---|---|---|
| username | Yes | |
| profile_url | Yes | Path of the public profile |
| username_claimed_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, so the mutation/non-destructive profile is covered. The description adds value beyond that by disclosing the authentication prerequisite and the session bootstrap path via start_login -- information an agent cannot get from the schema. It omits what happens when the username is already taken or whether the claim is idempotent, so it is good but not complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks: purpose plus constraints first, then a clearly labelled ACCESS prerequisite. It is front-loaded and easy to scan. The constraint sentence duplicates the schema pattern, a minor redundancy that costs it the top score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter mutation with annotations and an output schema already supplied, the description covers what is claimed, the validation rules, and the exact authentication path needed to invoke it. Nothing essential to a correct first invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter already carries the exact constraint text (3-30 chars, alphanumeric and underscores) plus a regex pattern. The description restates that rule verbatim rather than adding meaning such as case sensitivity, reserved names, or uniqueness-check behavior, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource -- 'Claim a unique username for the authenticated user's public profile' -- which is unambiguous and does not overlap with any sibling such as update_my_profile or get_profile. It stops short of explicitly contrasting with those siblings, but the operation is distinct enough that no agent would confuse them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives real preconditions: the caller must have a Proof account, either via PROOF_API_KEY or by opening a session with start_login, and names the recovery path ('then call this tool again'). It does not address alternatives such as updating an existing username or whether re-claiming is permitted, which keeps it out of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
confirm_domain_email_codeAInspect
Confirm domain email verification by submitting the code sent to the corporate email address.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| code | Yes | Verification code from the email |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | Domain record |
| message | Yes | |
| renewed | No | Sent when the call renewed the proof of an already verified domain. |
| verified | Yes | Whether control is confirmed after this call. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, and the description adds genuinely useful context: the Proof account/PROOF_API_KEY requirement and that a session from start_login unlocks the tool. It says nothing about code expiry, lockout after wrong attempts, rate limits, or the effect of a successful confirmation, which are the remaining behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded paragraphs: the action first, then the access prerequisite. No filler, though the access block is somewhat operational rather than tool-specific.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (2 required params, output schema present, annotations present), and the description covers the action plus the auth prerequisite that would otherwise block an agent. Failure-mode behavior is the only meaningful omission.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with both 'id' (Domain ID) and 'code' (verification code from the email) documented in the schema itself. The description only restates that the code comes from the corporate email and adds no format, length, or sourcing detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Confirm domain email verification') and specifies the mechanism ('by submitting the code sent to the corporate email address'), which separates it from start_domain_email_verification (which initiates the send) and resend_domain_email. It does not explicitly name those siblings, so it falls short of the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the flow ('then call this tool again' after a session opens), and the ACCESS paragraph gives a real prerequisite. However, it does not say when to call resend_domain_email instead if the code expired, nor what to do on a rejected code, so alternatives and exclusions are absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
connect_cloudflareADestructiveInspect
Connect a Cloudflare API token to a domain for automated DNS record management. Note: the API token will be visible in the AI conversation context.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| api_token | Yes | Cloudflare API token with DNS edit permissions |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so the bar is lower, and the description does add genuine value: a warning that the API token will be visible in conversation context, plus the auth/session prerequisite. What it does not disclose is the destructive dimension that the annotation flags, i.e. what happens to existing DNS records on the domain when a new token is connected, or whether the token is persisted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause, followed by a short security note and a compact ACCESS block. Nothing is padded, though the note and access block could be tightened into a single prerequisites sentence without loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the auth setup is well covered. The gap is against tool complexity: this is a destructive mutation touching live DNS, yet the description never says what is replaced or whether connecting again overwrites prior configuration, nor how it differs from the other connect_* tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with 'id' as Domain ID and 'api_token' constrained to a Cloudflare token with DNS edit permissions, so the baseline of 3 applies. The prose adds only that the token is sensitive in context, not additional meaning about the parameters themselves.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Connect a Cloudflare API token to a domain for automated DNS record management.' That is concrete and unambiguous about the outcome. However, it never distinguishes itself from the sibling connect_godaddy and connect_dns_provider tools, so an agent must infer which one to pick from the provider name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS paragraph gives real contextual guidance: a Proof account is required, PROOF_API_KEY must be set, or the agent should call start_login and then retry this tool. That is a concrete prerequisite chain the agent can act on. It stops short of any exclusion guidance (e.g. when to prefer connect_dns_provider instead), so it does not reach a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
connect_dns_providerADestructiveInspect
Connect a generic DNS provider to a domain using provider-specific credentials. Note: credentials will be visible in the AI conversation context.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| provider | Yes | DNS provider identifier | |
| credentials | Yes | Provider-specific credential key-value pairs |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so the safety profile is covered. The description adds genuinely non-obvious behavior: credentials will be exposed in the AI conversation context, and the call will fail until authentication is established. It does not describe what DNS changes are actually made on the provider side, which is the remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sections — what it does, then an explicit ACCESS block — with the credential-exposure warning front-loaded where it is most likely to be read. Minor redundancy in "then call this tool again," which is already implied by the retry instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive three-parameter mutation with a nested credential object, the definition covers the two things an agent most needs to avoid a blind failure: the auth precondition and the credential-visibility side effect. An output schema exists, so return values need no explanation; only the downstream DNS effect is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so id, provider, and credentials are all documented structurally. The description's phrase "provider-specific credentials" reinforces that the credentials object is free-form and varies by provider, but adds no format, required-key, or example detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: "Connect a generic DNS provider to a domain using provider-specific credentials." The word "generic" implicitly separates it from the provider-specific siblings connect_cloudflare and connect_godaddy, but those siblings are never named, so an agent must infer the split rather than being told.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operational context: a Proof account is required, and it spells out two paths (PROOF_API_KEY + restart, or start_login followed by a retry). What it does not do is state when to prefer this over connect_cloudflare or connect_godaddy — no explicit exclusion or alternative routing is present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
connect_godaddyADestructiveInspect
Connect GoDaddy API credentials to a domain for automated DNS record management. Note: the API key and secret will be visible in the AI conversation context.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| api_key | Yes | GoDaddy API key | |
| api_secret | Yes | GoDaddy API secret |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag readOnlyHint=false and destructiveHint=true, and the description adds two things they cannot convey: that the API key and secret will be exposed in the AI conversation context, and the exact auth flow for obtaining access. The one gap is that it never explains what the destructive flag means here – whether existing DNS records are overwritten.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the secret-exposure warning are front-loaded in the first two clauses, with access instructions following. Every sentence carries information, though the ACCESS block reads as internal shorthand slightly compressed for a first call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description covers the secrecy and auth prerequisites that dominate calling this tool. What remains missing is the consequence of the destructive hint on existing DNS configuration.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
All three parameters are documented at 100% schema coverage (id as Domain ID, api_key, api_secret), so the schema carries the semantics. The description only clarifies that the credentials are GoDaddy-specific, adding little beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Connect GoDaddy API credentials to a domain') plus the payoff ('automated DNS record management'), which lets an agent separate it from connect_cloudflare or connect_dns_provider. It does not explicitly name those alternatives, so it falls short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete preconditions and a recovery path: needs a Proof account, set PROOF_API_KEY and restart, or use start_login and then retry. It never says when to choose this over connect_cloudflare/connect_dns_provider/create_dns_credential, so the routing guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_accountAInspect
Create an account-bootstrap session for agent-driven onboarding. Public endpoint (no API key required). Returns a session id, channel-specific instructions, and — FOR TELEGRAM AND WHATSAPP ONLY — deep_link, qr_code (base64 PNG) and qr_text (UTF-8 text QR).
The endpoint is safe to call regardless of whether the submitted identity is new: completing verification transparently creates a User when none exists, or logs the user in when one already does. The response is intentionally uniform — the server does NOT reveal whether the identity is already registered (this would be a user-enumeration oracle). If the agent needs to distinguish new-vs-returning users, call get_current_user after verification and inspect the user's created_at.
EMAIL CHANNEL SENDS NOTHING HERE. The response carries email_sent=false and send_required=true: confirm with the user that the address is theirs, then call send_account_email. The other channels dispatch nothing either way — the user sends the first message themselves (reverse OTP).
Agent usage: (1) Call create_account with the user's chosen channel. (2) For email, confirm with the user and call send_account_email. On telegram/whatsapp pass deep_link to render_auth_link, which returns the clickable link with a QR code beneath it to you. On sms deep_link is an EMPTY STRING and render_auth_link will reject it — show sms_message, which is what the user sends; this response carries no destination number, so do not invent one. Do not hand qr_text to a link renderer either — it is the link already rendered as QR art; print it verbatim inside a fenced code block if a real terminal needs the QR. (3) Once your reply shows the user the challenge, call wait_for_account_creation with the session id until verification completes. On email the user must press "Sign in the browser that requested this" on the link's page — "Sign in here" signs in the browser they clicked from, and the wait then ends with "completed_elsewhere". (4) On verified, JWT + refresh cookies are set; proceed with whatever follow-up the agent was asked to do.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
| Name | Required | Description | Default |
|---|---|---|---|
| No | Email address. Required for email channel. | ||
| channel | Yes | Authentication channel the user will verify through | |
| phone_number | No | E.164 phone number. Required for SMS channel (determines DID routing). |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| type | No | Outcome of an account-session creation. `account_creation` means a new User will be written on verification. `login` indicates the submitted identity matched an existing User and the session will log them in. |
| No | ||
| status | No | Status of an auth session. `completed_elsewhere` (terminal, no cookies): an email sign-in the person completed in ANOTHER browser by pressing "Sign in here" on the link's page — this session will never become `verified`. |
| channel | No | Authentication channel |
| qr_code | No | Base64-encoded PNG QR code for the deep link |
| qr_text | No | UTF-8 text QR for terminal/agent rendering |
| user_id | No | |
| sms_code | No | Short code for SMS-channel reverse-OTP |
| deep_link | No | |
| created_at | No | |
| email_sent | No | |
| expires_at | No | |
| email_error | No | |
| sms_message | No | |
| verified_at | No | |
| instructions | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: public endpoint, deliberately uniform response to avoid a user-enumeration oracle, email channel sends nothing (email_sent=false / send_required=true), SMS returns empty deep_link that render_auth_link rejects, and JWT + refresh cookies are set on completion. It also warns that most clients fold tool results away, which is operational context no annotation could carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and the workflow is laid out as a scannable numbered sequence with reserved-capital emphasis on critical facts. It is on the long side, and a few asides (e.g. "The other channels dispatch nothing either way") could be tightened without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a multi-step, channel-varying, side-effect-bearing bootstrap call, nothing an agent needs is missing: return payload per channel, verification semantics, post-verification state, and the requirement to surface output in the agent's own reply text. Output schema exists, yet the description still adds the interpretation an agent needs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description earns above that by explaining channel-dependent requirements — email address for the email channel, E.164 phone for SMS DID routing, and which channels return deep_link/qr versus sms_message.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Create an account-bootstrap session for agent-driven onboarding") and immediately scopes it as a public, no-API-key endpoint. It also names its workflow companions (send_account_email, render_auth_link, wait_for_account_creation, get_current_user), which separates it from the many sibling session/login tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit numbered agent workflow, states when to call the alternative (get_current_user after verification to distinguish new vs. returning users), and gives negative guidance (don't hand qr_text to a link renderer, don't invent a destination number for SMS, don't wait before showing the user the challenge).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_api_keyAInspect
Create a new API key. The secret key value is returned ONLY in this response — store it securely. Note: the secret will be visible in the AI conversation context. Optionally bind the key to a sub-account via profile_id — outbound messages sent with the key are then branded as that sub-account.
Agent usage: This operation requires 2FA. Before calling, complete the 2FA flow: (1) call start_2fa with action_type "api_key_create" and the user's preferred channel, (2) tell the user a code was sent and wait for them to verify, (3) poll get_2fa_status until status is "verified", (4) then call create_api_key — the backend session will be elevated. If you get a 403, the 2FA session has expired — restart the flow.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Human-readable key name | |
| scopes | No | Permission scopes for the key | |
| profile_id | No | Bind the new key to a sub-account you own (24-hex id). Immutable after creation; omit for an unbound account-wide key. | |
| environment | No | Key environment (default: production) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| key | Yes | The full API key. Returned only in this response; it cannot be read again. |
| name | Yes | |
| prefix | Yes | |
| scopes | Yes | |
| warning | Yes | |
| created_at | Yes | |
| profile_id | Yes | Sub-account (PublicProfile) the key is bound to; null for unbound keys. |
| environment | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses that the secret is returned only in this response, must be stored securely, and will be visible in AI conversation context. It also explains the 2FA elevation flow and the behavioral consequence of profile_id binding, which is substantial. It does not elaborate on rate limits or what the returned object contains, but the output schema covers return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and the critical one-time secret warning, followed by ordered 2FA steps and access requirements. Despite its length, every section is necessary for safely invoking this privileged creation tool, and there is no redundant filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of 2FA, account access, one-time secret handling, and optional sub-account binding, the description covers the practical invocation path well. Return-value details are appropriately left to the output schema, though additional guidance on choosing scopes could improve completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters, including scopes, profile_id, and environment. The description adds useful meaning for profile_id by explaining sub-account branding, but otherwise does not deepen parameter semantics beyond the schema baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Create a new API key.' It also clarifies that the secret is returned only once and that profile_id can bind the key, which distinguishes the operation from listing, revoking, or regenerating existing keys without naming those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context and prerequisites: the operation requires 2FA, needs a Proof account, and should be called only after the 2FA flow is verified. The 403 recovery path is explicit, though it does not directly compare this tool with alternatives such as regenerate_api_key or list_api_keys.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_authorizationAInspect
Create a new authorization request. Authorizations grant permission to send confirmations to a user via a specific channel. The user must approve the authorization before confirmations can be sent.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| bsuid | No | WhatsApp Business-Scoped User ID (alternative to phone for WhatsApp channel) | |
| phone | Yes | Target phone number in E.164 format (e.g., +15551234567) | |
| scope | No | Authorization scope (default: confirmations) | |
| channel | Yes | Channel for sending confirmations | |
| hitl_id | Yes | HITL configuration ID to link this authorization to | |
| recipient | Yes | Channel-specific recipient identifier (chat_id for Telegram, phone/BSUID for WhatsApp) | |
| expires_in | No | Expiry in seconds (max 90 days, default 90 days) | |
| business_name | No | Deprecated and ignored: the consent message always names the approval setup's sub-account. Leave it out. | |
| business_profile_id | No | Sub-account to record on the authorization (does not change the name the person sees) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bsuid | No | WhatsApp Business-Scoped User ID |
| phone | No | |
| scope | Yes | Scope of the authorization. `identity_challenge` is the Proof of Me scope. |
| status | Yes | Status of an authorization |
| channel | Yes | Channel authorized for sending confirmations |
| hitl_id | Yes | |
| recipient | No | Channel-specific recipient identifier (chat_id for Telegram, phone or BSUID for WhatsApp) |
| created_at | Yes | |
| expires_at | Yes | |
| business_name | Yes | The name the consent message carried: the approval setup's sub-account name, never a name typed in the request. |
| authorization_url | Yes | URL to send to the user for authorization |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false and destructiveHint=false; the description adds real behavioral context beyond that — the created object is inert until the end user approves it, and creation requires a Proof account with PROOF_API_KEY configured plus a server restart. It does not cover whether repeated calls create duplicates or how long the pending state lasts, which is why it is not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded paragraphs: what the tool creates and the approval semantics first, then the access prerequisite. Every sentence earns its place, though the ACCESS preamble is operational noise for an already-authenticated agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 9 parameters, an output schema, and thin annotations, the definition supplies what the structured fields cannot: the approval workflow and the account prerequisite. It is nearly complete for the calling decision; the remaining gap is the relationship to sibling authorization/confirmation tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including enum values, patterns, and the deprecation of business_name, so the schema already carries parameter meaning. The description adds nothing about individual fields (for example, phone versus bsuid per channel), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ("Create a new authorization request") and explains the domain concept: an authorization grants permission to send confirmations to a user over a channel, and the user must approve it. That distinguishes it from generic creation tools, but it never names the adjacent siblings it could be confused with (create_confirmation, request_hitl_authorization, create_verification_request), so the differentiation stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the agent learns an authorization is a prerequisite for sending confirmations, and the ACCESS note usefully excludes start_login as a way to unlock the tool. However, there is no explicit guidance on when to call create_authorization versus request_hitl_authorization or create_confirmation, nor on what to do if an authorization already exists.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_chat_id_discoveryAInspect
Create a Telegram chat ID discovery token. Returns a deep_link, qr_code (base64 PNG), and qr_text (UTF-8 text QR for terminal display). The user opens the link in Telegram, which reveals their chat ID for HITL config setup.
Agent usage: pass the response's deep_link to render_auth_link so the user can click or scan it. Never hand qr_text to a link renderer — it is that same link already rendered as QR art. Print it verbatim inside a fenced code block only when a real terminal needs the QR. Then poll poll_chat_id_discovery with the returned token until the chat_id appears. Use the discovered chat_id when creating a HITL config with a Telegram channel.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| token | Yes | |
| qr_code | Yes | QR code data URL for the deep link |
| qr_text | Yes | UTF-8 text representation of the QR code for terminal/agent display |
| deep_link | Yes | |
| expires_in | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint=false/destructiveHint=false annotations by disclosing the auth prerequisite (PROOF_API_KEY, restart required, start_login does not unlock it) and the client-level behavior that users never see tool results, which changes how the agent must respond. It also explains what each returned artifact is and what it must not be used for.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then a labeled 'Agent usage' block and an access note — good structure. Minor waste: the user-invisibility paragraph mentions 'SMS text and number' and inbox checks, which belong to other tools and do not apply here.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still usefully names the returned fields and their roles in the flow, plus the auth gate and the downstream poll step. Nothing an agent needs to invoke this correctly and continue the workflow is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter meaning for the description to carry; it correctly spends its words on the returned token and artifacts instead.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a Telegram chat ID discovery token') and immediately names the three return artifacts (deep_link, qr_code, qr_text). It is clearly distinguishable from siblings poll_chat_id_discovery and wait_for_chat_id_discovery, which it explicitly hands off to.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit 'Agent usage' sequence: pass deep_link to render_auth_link, do not pass qr_text to a renderer, then poll poll_chat_id_discovery until chat_id appears, then use it in a Telegram-channel HITL config. It names the follow-up tools and the terminal-state condition ('until the chat_id appears').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_circleAInspect
Create a Circle — a named group of trusted contacts (the people-primitive powering Proof-Me and Approvals-on-Circle). Optionally seed initial members; each member's declared channels are stored so they can be invited to enroll.
Agent usage: after creating a Circle, add members with add_circle_member (or seed them here), then invite_circle_member to mint the enrollment deep link each contact taps to bind their messenger identity.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Human-readable name for the Circle | |
| members | No | Initial members (name + optional declared channels) | |
| owner_name | No | How this Circle's members know its owner ("Dad", "Giorgi"). The bots name the owner by it; while it is empty they name nobody — the Circle's name labels the group, never the person. Trimmed by the API; null or an empty value clears it. | |
| profile_id | No | Public profile (sub-account) to bind for branded messages — create-only | |
| proof_me_enabled | No | Enable Proof-Me drills for this Circle |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| name | No | |
| status | No | Lifecycle state of a Circle (archived = soft-retired) |
| members | No | |
| user_id | No | |
| created_at | No | |
| owner_name | No | How this Circle's members know its owner; null when unset |
| profile_id | No | |
| updated_at | No | |
| environment | No | |
| member_count | No | |
| proof_me_enabled | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description goes further by disclosing the auth prerequisite, the fact that start_login will not satisfy it, and what happens to declared member channels (stored so members can be invited later). It does not cover duplicate-name behavior, idempotency, or what the create response contains, which the presence of an output schema partly excuses.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short paragraphs, front-loaded with the definition, then the agent workflow, then access constraints — an agent reading only the first sentence already knows what the tool does. The access paragraph's restart instruction is slightly operationally verbose but earns its place by preventing a failed call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a create tool with five parameters, full schema descriptions, annotations, and an output schema, the description supplies exactly what structured fields cannot: the domain model, the follow-on workflow, and the auth gate. Nothing an agent needs before calling it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description still adds value by explaining that members may be seeded at creation as an alternative to add_circle_member and that their declared channels persist for later enrollment. It says nothing about profile_id or proof_me_enabled beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ("Create a Circle") and defines the resource in domain terms: a named group of trusted contacts powering Proof-Me and Approvals-on-Circle. That framing distinguishes it cleanly from list_circles, get_circle, update_circle and delete_circle without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The "Agent usage" paragraph gives an explicit sequence: create, then add_circle_member or seed members here, then invite_circle_member to mint the enrollment link. It also states a hard exclusion — "start_login does NOT open this tool" — and the prerequisite (set PROOF_API_KEY and restart), which is more than most definitions offer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_circle_member_drillAInspect
Fire an on-demand Proof-Me drill against one enrolled member — a real cross-channel identity challenge carrying the scheduled-safety-check label (the account owner practices confirming). Complements the automated daily drill + monthly reinforcement sweeps. On Pay as you go a live key is refused 422 plan_upgrade_required; a test key is not, and its drill reaches the member on Telegram only (400 no_channel when they have no verified Telegram channel).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| member_id | Yes | Member ID to drill |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| status | No | |
| confirm_channel | No | Channel the CONFIRM was dispatched on |
| single_channel_warning | No | True when the owner has only one channel, so the CONFIRM ran on the same channel (degraded) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the supplied annotations (readOnlyHint=false, destructiveHint=false), the description discloses the substantive behavioral traits: an actual challenge is dispatched to a real person, it carries the scheduled-safety-check label, and specific failure modes and their codes are given (422 plan_upgrade_required for live keys on Pay as you go, 400 no_channel when the member lacks a verified Telegram channel). It also explains the test-key asymmetry, which materially changes what an agent should expect. Nothing contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the 'drill vs automated sweeps' framing, then grouped into error-behavior and access blocks. Dense but nearly every clause carries operational weight; the parenthetical '(the account owner practices confirming)' is the only mildly expendable phrase.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation with an output schema, the description covers purpose, plan gating, channel precondition, and credential setup (PROOF_API_KEY + restart, plus the explicit note that start_login does not unlock it). The main residual gap is what an agent should do after firing — e.g., whether results are observed via the output schema or polled elsewhere — and any rate-limit or idempotency expectations for repeated drills.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: the member_id must identify an *enrolled* member, and that member needs a verified Telegram channel (under a test key) or the call fails with 400 no_channel. That constraint is not expressible in the schema's 24-hex-char pattern and directly informs parameter selection.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource — 'Fire an on-demand Proof-Me drill against one enrolled member' — and immediately characterizes it as 'a real cross-channel identity challenge carrying the scheduled-safety-check label.' It also positions the tool against automated siblings ('Complements the automated daily drill + monthly reinforcement sweeps'), so an agent can separate this on-demand drill from scheduled sweeps without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear context for when to reach for this tool: on-demand, single member, versus the automated daily/monthly sweeps. It further gates usage by plan ('On Pay as you go a live key is refused 422 plan_upgrade_required') and by channel availability. It stops short of naming a direct alternative sibling (e.g., create_verification_request or trigger_verification) for the case where this tool is unavailable, so it is slightly under-specified on exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_confirmationAInspect
Create a HITL confirmation request. Sends an approval request to the channels configured on the referenced HITL config. First response wins.
Agent usage: The HITL config referenced by hitl_id must be authorized before you can create confirmations. If this returns a 403 or "not authorized" error, call request_hitl_authorization on the HITL config first, then wait for the user to approve via the messaging channel. After creating a confirmation, poll get_confirmation to check for approval/denial, or, if the user (the HITL config owner) will decide it themselves, use get_confirmation_approval_link for their own approval link.
Encryption is NOT optional: a HITL config cannot send confirmations without a keypair, the human approves by decrypting in their browser, and message must be a JSON ciphertext envelope. Plaintext is refused with 400 message_not_encrypted; an envelope sealed to another key with 400 message_key_mismatch. Choose the version by who must be able to decrypt:
v1 (single-recipient): wraps the content key for the config owner only. Use ONLY when there are no enrolled non-owner approvers — with approvers enrolled it is refused with 400
envelope_missing_approvers.v2 (multi-recipient): additionally wraps the content key for each enrolled approver via an
approver_ekmap, so every approver can decrypt. Build it with the SDKencryptMessageV2(plaintext, ownerPublicKey, hitlId, approverKeys)after fetching the approvers via the SDKgetApproverKeys(hitlId)(GET /api/v1/hitl/:id/approver-keys). AAD is thehitlId.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| hitl_id | Yes | HITL config ID whose channels will receive the approval request | |
| message | Yes | The client-encrypted ciphertext envelope as a JSON string (v1 or v2) — NOT the human-readable text. Encrypt the sentence the approver should read; passing it directly is refused with 400 `message_not_encrypted`, because the approval page can only decrypt an envelope. | |
| proof_expiry_days | No | Per-request proof expiry override in days (7, 30, 90, or 365) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| status | No | Status of a confirmation request. A confirmation that times out is `denied`, with `response.channel` `system` and `response.text` `timeout`. |
| hitl_id | No | |
| message | No | The stored ciphertext envelope, echoed back verbatim. The server never sees the plaintext, so this is never the human sentence — the approver decrypts it in their browser. |
| resends | No | Every "Send again" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it. |
| response | No | The decision and its evidence (null while pending) |
| created_at | No | |
| timeout_at | No | When this confirmation will time out |
| updated_at | No | |
| proof_token | No | Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`) |
| resolved_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare read=false/destructive=false, so the description carries the rest and does it thoroughly: the request fans out to configured channels, the first response wins, encryption is mandatory, and specific 400 error codes (message_not_encrypted, message_key_mismatch, envelope_missing_approvers) are documented. It also discloses the access precondition (PROOF_API_KEY required, start_login will not help), which is non-obvious failure-mode information.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose sentence, then grouped into usage, then encryption rules — logical for a multi-step tool. It is long, and the plaintext-refusal error code is stated both in the description body and again in the message schema, so a small amount of text is duplicated rather than additive.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with an output schema and three documented parameters, the definition covers everything an agent needs before calling: authorization prerequisite, envelope construction, failure signals, and the two routes for checking the outcome. Return values are correctly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds substantial meaning beyond it: it explains the v1 vs v2 envelope choice by 'who must be able to decrypt', the enrolled-approver rule that makes v1 fail, the approver_ek map, and the SDK helpers encryptMessageV2/getApproverKeys with the AAD being hitlId. That is decision-relevant construction guidance not present in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Create a HITL confirmation request' and immediately explains the effect — an approval request is broadcast to the channels on the referenced HITL config, with 'First response wins' as the resolution rule. This clearly distinguishes it from siblings like get_confirmation, wait_for_confirmation, and create_verification_request.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Agent usage' block states the prerequisite (hitl_id must be authorized), the recovery path on 403 (call request_hitl_authorization then wait for channel approval), and names both follow-up alternatives — get_confirmation for polling and get_confirmation_approval_link when the config owner decides themselves — with the condition that selects each.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_delegationAInspect
Create a delegation (Proof of Delegation): a control-proven domain authorizes a typed url/purl artifact and receives a publishable signed token. The attestation is that the domain's controller authorized this artifact — nothing more; it says nothing about the artifact or the business behind it. Each mint is a billable proof. A requested lifetime longer than the control proof's remainder is rejected, never truncated. The result carries the publishable token AND the DERIVED effective_status/is_valid — the same pair the list and get tools return, so the shape does not depend on which verb produced it.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| delegate | Yes | The typed artifact being authorized | |
| expires_in | No | Lifetime in seconds (must not exceed the control proof's remainder) | |
| control_proof | Yes | Public handle (ph_ctl_<32 hex>) of YOUR active domain control proof |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| scope | No | Deprecated. Delegation schema 2.0 carries no scope; this array stays for the SDKs released before it: the scope a delegation issued before schema 2.0 was stored with, otherwise empty. Removed in the next major version. |
| token | No | The signed delegation JWT — the PUBLISHABLE artifact (publish it in your MCP server card under `_meta` → `holdings.proof/delegation`). Same key, algorithm and JWKS as proof tokens |
| status | No | The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on |
| delegate | No | Typed delegate identifier |
| is_valid | No | True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above |
| issued_at | No | |
| principal | No | The proven domain that authorized the delegate — derived from the control proof, never client input |
| created_at | No | |
| expires_at | No | Never later than the control proof's own expiry at issuance (effective expiry is min of the two) |
| revoked_at | No | |
| environment | No | |
| control_proof | No | The control proof handle this delegation points down to |
| delegation_id | No | Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint |
| revoked_reason | No | |
| effective_status | No | DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: each mint is billable, an over-long expires_in is rejected rather than silently truncated, and the response carries derived effective_status/is_valid so it matches list/get output. Auth setup is spelled out at the environment level. What is missing is any note on reversibility/idempotency — whether re-minting the same delegate creates a duplicate billable proof — which matters for a non-destructive-but-metered write.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the definition, then constraints, then billing, then access — a sensible order with no filler. It is somewhat dense and the closing clause ('so the shape does not depend on which verb produced it') could be trimmed, but every sentence conveys operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a nested-object, three-parameter write with an output schema, the description covers the domain concept, the failure mode, the billing implication, and the credential prerequisite. Since an output schema exists, it is not obligated to explain return values, yet it tells the agent enough about the returned pair to plan downstream calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, and the description earns an extra point by adding real semantics: expires_in is bounded by the control proof's remaining lifetime and fails rather than truncates, and control_proof must be the caller's own active domain proof, not any handle. It does not clarify server-side canonicalization effects on the delegate value beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a delegation (Proof of Delegation)') and then defines the exact semantics of the artifact: a control-proven domain authorizes a typed url/purl and receives a publishable signed token. It also scopes what the attestation does NOT claim ('nothing more; it says nothing about the artifact or the business behind it'), which separates it cleanly from siblings like create_authorization, verify_delegation, and get_delegation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete preconditions and an explicit exclusion: needs a Proof account, PROOF_API_KEY must be set and the server restarted, and 'start_login does NOT open this tool' — a genuinely useful anti-pattern warning given start_login exists as a sibling. It stops short of naming the alternative verb to call when you only want to read or verify an existing delegation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_dns_credentialADestructiveInspect
Store DNS provider credentials for automated domain verification. Note: credentials will be visible in the AI conversation context.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| provider | Yes | DNS provider identifier (e.g. cloudflare, route53, digitalocean) | |
| credentials | Yes | Provider-specific credential key-value pairs |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | Yes | |
| is_valid | Yes | |
| provider | Yes | |
| created_at | Yes | |
| updated_at | Yes | |
| last_used_at | No | When the credential last made a DNS change; absent until it has. Sent by the list only. |
| domains_count | Yes | |
| validation_error | No | Why the last check refused the credential; absent unless one did. Sent by the list only. |
| last_validated_at | No | When the credential was last checked against its provider; absent when never recorded. Sent by the list only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds real behavioral context beyond the annotations, most notably that credentials become visible in the AI conversation context — a non-obvious and important side effect for a secret-storing tool. It also states the auth prerequisite and restart requirement. It does not explain storage lifetime, encryption, or how stored credentials relate to list_dns_credentials/delete_dns_credential cleanup, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one sentence, followed by a security warning and an access block, with no filler. The ACCESS section is slightly verbose but earns its space by unlocking invocation for an unauthenticated agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists and both parameters are fully documented in the schema, the remaining burden on the description is behavior and access, both of which are covered — including the credential-exposure caveat and the login path. An agent has enough to call it correctly, with only sibling differentiation missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with both provider (including example identifiers) and the provider-specific credentials object documented in the schema itself. The description adds no syntax or per-provider credential key guidance, so the baseline 3 applies — the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb and resource: store DNS provider credentials, tied to the purpose of automated domain verification. It is clear what the tool does, but it never distinguishes itself from close siblings such as connect_dns_provider, connect_godaddy, or verify_domain_with_credentials, so an agent cannot route between them from the description alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the agent infers it should call this to persist credentials before automated verification. The ACCESS paragraph is genuinely useful setup guidance (PROOF_API_KEY or start_login), but it explains authentication, not when to pick this tool over the sibling connectors that also register DNS providers.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_hitlAInspect
Create a HITL (Human-in-the-Loop) config. Defines which messaging channels receive approval requests and the default timeout.
Agent usage: After creating a HITL config, you must call request_hitl_authorization before it can be used with create_confirmation. For Telegram channels, use create_chat_id_discovery first to discover the user's chat ID, then include it in the channel config.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Human-readable name for this HITL config | |
| channels | No | Messaging channels for approval requests (telegram or whatsapp). Either channels or circle_id is required. | |
| circle_id | No | Route approvals through this circle's members instead of listed channels (24 hex characters) | |
| profile_id | No | The sub-account (24 hex characters) whose branding the approval messages carry; omitted, the primary | |
| timeout_seconds | No | Default timeout in seconds (60–86400, default: 3600) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | No | |
| status | Yes | Status of a HITL configuration |
| keypair | Yes | Encryption keypair metadata (null if not configured) |
| user_id | Yes | Owner user ID (useful for SDK encryption AAD) |
| channels | Yes | |
| circle_id | No | Backing Circle for a circle-backed Approvals config (null for channel-list configs) |
| created_at | Yes | |
| profile_id | No | |
| updated_at | Yes | |
| environment | Yes | |
| timeout_seconds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description adds the non-obvious access gate (PROOF_API_KEY must be set and the server restarted) and the lifecycle state that a new config is unusable until authorized. That is real behavioral context beyond structured fields. It does not address naming collisions or what happens on duplicate creation, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then two clearly labeled blocks for agent usage and access gating. Dense but every sentence carries actionable content; the only minor cost is that the ACCESS block is stated in three short fragments rather than one.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations and an output schema present, the description covers the remaining gaps an agent needs: prerequisite access, mandatory follow-up call, and channel-specific discovery. It leaves unstated whether channels and circle_id are mutually exclusive and what happens when neither is supplied, which matters because only 'name' is in the schema's required list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema cannot: it tells the agent where a Telegram chat_id value comes from (create_chat_id_discovery) and frames timeout_seconds as a default rather than a per-request override. The either/or relationship between channels and circle_id is only asserted in the schema text, not reinforced here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a HITL config') and immediately scopes what the resource governs: which messaging channels receive approval requests and the default timeout. This separates it cleanly from request_hitl_authorization, create_confirmation, and update_hitl, which are named in the usage section.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit sequencing rules with named siblings: request_hitl_authorization must be called after creation and before create_confirmation will work, and Telegram channels require create_chat_id_discovery first. It also rules out a plausible-but-wrong path by stating start_login does NOT unlock this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_identity_challengeAInspect
Create a Proof-Me cross-channel identity challenge (CONFIRM) for an enrolled Circle member. The account holder approves/denies on a channel different from the one the suspicious contact reached the member on.
Agent usage: poll get_identity_challenge with the returned ID until it leaves pending (confirmed, denied, cancelled, failed, expired or revoked).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| circle_id | Yes | Circle that holds the member | |
| member_id | Yes | Enrolled Circle member initiating the check | |
| suspicious_channel | No | Channel the suspicious contact reached the member on; defaults to the member channel |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| status | Yes | The one status every read reports. `pending` — waiting for the person being checked; `confirmed` — they confirmed; `denied` — they denied; `cancelled` — whoever started the check withdrew it; `failed` — the check could not be delivered; `expired` — nobody answered in time; `revoked` / `suspended` — the confirmation's proof was revoked or suspended (`POST /proofs/{proof_id}/revoke` or `/suspend`; revoking a denial's proof leaves it `denied`), or — `revoked` only — the member being checked was removed from the Circle while the check was still pending, which leaves `proof_id` null. Removing a member is not guaranteed to revoke a confirmation they already gave; revoke that one by its `proof_id`. A proof that merely reached its own expiry still reads `confirmed`; whether its token is still valid is `POST /proofs/validate`'s answer. |
| channel | No | Channel the CONFIRM was dispatched on (GET) |
| is_drill | No | True for a drill (scheduled, or started from the dashboard) rather than a real check (GET) |
| proof_id | No | Public handle of the decision's proof — what `POST /proofs/{proof_id}/revoke` takes. Null until a decision minted one (GET). |
| circle_id | No | The Circle the check belongs to (GET) |
| created_at | No | ISO 8601 timestamp |
| expires_at | No | ISO 8601 timestamp |
| proof_token | No | Signed proof token, present once the person being checked decided |
| resolved_at | No | ISO 8601 timestamp of the decision — the CONFIRM, the DENY, the cancellation or the delivery failure — or null while the check is unanswered and after a timeout. |
| confirm_channel | No | Channel the CONFIRM was dispatched on (POST) |
| single_channel_warning | No | True when the account holder has only one channel, so the CONFIRM ran on the same channel as the suspicious contact (degraded) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: discloses that it is asynchronous with a defined terminal-state set (confirmed, denied, cancelled, failed, expired, revoked), that the approval happens on a channel different from the suspicious one, and that authentication requires PROOF_API_KEY plus a server restart. The explicit note that start_login does NOT unlock this tool is unusually valuable context for an agent avoiding a failed call loop.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight blocks — what it does, the approval mechanic, the agent polling loop, and the access prerequisite — with the purpose front-loaded and no filler sentences. Every line carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description still covers prerequisites, async behavior, and terminal states. It omits polling cadence/backoff and failure recovery, which an agent managing a multi-second wait would want.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real semantics: the suspicious_channel parameter is relational — it drives which channel the account holder must be reached on, namely one different from it. It still does not explain circle_id/member_id relationships beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource: create a Proof-Me cross-channel identity challenge (CONFIRM) for an enrolled Circle member, and the second sentence explains the cross-channel mechanic that makes this distinct from a plain confirmation. It stops short of naming a concrete sibling (create_confirmation, create_multi_channel_verification) as the alternative, so differentiation is implied rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear operational workflow (poll get_identity_challenge with the returned ID until it leaves pending) and states the precondition that the member must be enrolled in a Circle. It does not say when to prefer this over the other confirmation/verification tools or when it is inappropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_multi_channel_verificationAInspect
Create a multi-channel phone verification: one phone number challenged over several channels at once (OR / first-wins). The first channel the user completes wins, yields a single proof token, and cancels the losing siblings. Exactly one proof is billed, at the winning channel's completion — not one per channel, and nothing at creation.
Agent usage: the response includes a group_id (format vg_) and a channels array — each block carries a deep_link (WhatsApp/Telegram) or an sms_message to present to the user — pass the deep_link to render_auth_link. A block's qr_text is that same link already rendered as QR art, not an alternative address: print it verbatim inside a fenced code block or leave it out. Poll get_multi_channel_verification_status with the group_id to track completion and retrieve the proof token when a channel verifies.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Asset type — only "phone" is supported | |
| channels | Yes | 1-4 unique channels attempted in parallel (first to complete wins) | |
| identifier | Yes | Phone number in E.164 format | |
| profile_id | No | Sub-account whose name and templates the request uses; omitted: the key's sub-account, else the primary | |
| client_metadata | No | Your own key-value data, stored with the request | |
| external_user_id | No | Your application user ID for grouping verifications | |
| proof_expiry_days | No | Per-request proof expiry override in days (1-365) |
Output Schema
| Name | Required | Description |
|---|---|---|
| type | No | |
| status | No | Current status of the verification |
| channels | No | |
| group_id | No | Verification group ID (vg_ prefix) |
| created_at | No | |
| expires_at | No | When every channel challenge expires |
| identifier | No | |
| client_metadata | No | |
| external_user_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description goes far beyond by explaining first-wins cancellation of losing siblings, that exactly one proof is billed at the winning channel's completion and nothing at creation, and the critical client behavior that users never see tool output. That last point changes how the agent must format its reply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but segmented into purpose, agent usage, UX warning, and access, with the core semantics front-loaded. Nearly every sentence carries operational weight, though the access/auth paragraph could be tightened slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter creation tool with nested objects and an output schema, the definition covers the full lifecycle: creation, response shape, follow-up polling, proof retrieval, billing, and auth setup. Nothing an agent needs in order to call and act on this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description earns more: it explains that the channels array is raced in parallel with first-completion winning, that the returned channels blocks each carry a deep_link or sms_message, and that qr_text is the same link pre-rendered rather than an alternate address — a distinction the schema cannot convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ("Create a multi-channel phone verification") and immediately defines the mechanic: one phone number challenged over several channels with OR / first-wins semantics. It is unambiguously distinct from the sibling polling tool get_multi_channel_verification_status, which it names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent what to do after creation (pass deep_link to render_auth_link, poll get_multi_channel_verification_status with group_id) and what not to rely on (start_login does NOT open this tool). Prerequisites — PROOF_API_KEY, server restart — are stated with a concrete remedy.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_profileADestructiveInspect
Create a new profile with optional display name, bio, avatar, business info, email branding (theme, support email), and theme settings.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| bio | No | Profile bio | |
| theme | No | Profile theme settings | |
| is_public | No | Whether the profile is publicly visible | |
| avatar_url | No | Avatar as base64 data URI or URL (~75KB limit) | |
| is_primary | No | Set as primary profile | |
| email_theme | No | Theme of this sub-account's emails | |
| is_business | No | Whether this is a business profile | |
| display_name | No | Display name | |
| business_name | No | Business name | |
| support_email | No | Support email this sub-account's messages show |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bio | No | |
| theme | Yes | Profile theme customization |
| username | No | Absent until a username is claimed |
| is_public | Yes | |
| avatar_url | No | A URL or a data URI; null once cleared |
| created_at | Yes | |
| is_primary | Yes | |
| profile_id | Yes | The public id used in profile URLs |
| updated_at | Yes | |
| view_count | Yes | |
| email_theme | Yes | Theme of this sub-account's emails; null when unset (read as `dark`). |
| is_business | Yes | |
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| custom_links | Yes | |
| display_name | No | |
| business_name | No | |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
| support_email | Yes | Support address shown in this sub-account's messages; null when unset. |
| show_delegations | Yes | |
| verification_level | Yes | Always 'basic'; no levels are computed; removed in the next major. |
| show_proof_channels | Yes | |
| show_verification_dates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so the write/mutating nature is known; the description's real contribution is the authentication prerequisite and restart requirement, which the annotations do not convey. It does not address why a create carries destructiveHint=true, whether the operation is reversible via delete_profile, or whether profile count or primary-profile conflicts are constrained.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact paragraphs: purpose first, access constraint second, with no filler or repetition. The all-caps ACCESS block is slightly shouty but is front-loaded enough to be actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, annotations cover the safety profile, and all 10 parameters are documented, so the description only needed to add purpose and access context, which it does. The remaining gap is behavioral detail around primary-profile selection and reversibility for a 10-parameter mutation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% across all 10 parameters including the nested theme object, so the schema already carries field-level meaning. The description's field list largely restates those categories and adds no syntax, defaults, or interaction rules (e.g. how is_primary behaves when a primary already exists, or the avatar size limit already noted in the schema).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ("Create a new profile") and enumerates the optional field families it accepts (display name, bio, avatar, business info, email branding, theme), so an agent immediately knows what the call produces. It does not explicitly differentiate from nearby siblings such as update_profile or create_account, which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit precondition (needs a Proof account, set PROOF_API_KEY and restart) and a negative routing statement ("start_login does NOT open this tool"), which prevents a plausible wrong-path attempt. It stops short of saying when to create versus update an existing profile, so the use-case selection guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_sessionAInspect
Create a new phone verification session. Returns deep_link, qr_code (base64 PNG), and qr_text (UTF-8 text QR for terminal display). Sessions provide a hosted verification flow with callbacks.
Agent usage: After creating a session, pass the response's deep_link to render_auth_link so the user can open or scan it. Never hand qr_text to a link renderer — it is that link already rendered as QR art. Print it verbatim inside a fenced code block only when a real terminal needs the QR. On sms the person texts a short code from the number being proven, as in SMS login: deep_link is an sms: link to our default number with the message pre-filled, so render it the same way, and also show sms_message (what they send) with the numbers in sms_dids (one per region, each with its own QR), because a person reading on a computer texts from their phone. They get no reply SMS. An SMS proof can still be revoked about a minute after the session completes, if the delayed spoof check finds the sender was not a real mobile line, so before relying on it check it with validate_proof. Then use wait_for_session to poll until the session reaches a terminal state (verified, failed, or expired).
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | How the person proves the number: telegram or whatsapp (the bot reads it from their account) or sms (they text a short code from it). No phone number is sent | |
| context | No | ||
| profile_id | No | Sub-account whose name and templates the bot uses; omitted: the key's sub-account, else the primary | |
| client_metadata | No | Your own key-value data, stored with the session |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | Session id |
| status | No | |
| channel | No | How the person proves the number: `telegram` or `whatsapp` (the bot reads the number from their account), or `sms` (they text a short code from the number to one of ours). |
| qr_code | No | Base64-encoded PNG QR code for `deep_link` |
| qr_text | No | UTF-8 text QR for `deep_link`, for terminal/agent rendering |
| sms_code | No | The short code the person texts (`sms` only) |
| sms_dids | No | Every number an `sms` session's code can be texted to, one per configured region (a region with no number is absent), each with its own QR code. `deep_link` uses the default region's number; the request comes from your server, so nothing in it says where the person is. |
| deep_link | No | Opens the messenger (`https://t.me/…`, `https://wa.me/…`) or the messaging app (`sms:<number>?body=…`) with what the person sends |
| expires_at | No | |
| sms_message | No | The message to send, as pre-filled in the links (`sms` only) |
| instructions | No | One line telling the person what to do |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, destructiveHint=false), the description discloses the response shape, the fact that the user never sees tool results, the SMS flow's quirks (no reply SMS, delayed spoof check that can revoke a proof about a minute after completion), and the authentication prerequisite (PROOF_API_KEY plus restart, and that start_login does not open this tool). That is substantial behavior an agent could not get from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and return values are front-loaded and every paragraph carries operational content, but the draft is long and slightly redundant — the 'user does not see tool results' point is made once about render_auth_link's output and again as a directive before waiting/polling. The SMS paragraph in particular is dense enough that a reader may need a second pass.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a multi-step, stateful creation tool with nested parameters, the definition covers creation, rendering, polling, revocation risk, and credential setup. An output schema exists, so the description's return-value summary is a convenience rather than a necessity, and nothing an agent needs in order to call this correctly appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75% and the description adds real meaning about channel behavior: telegram/whatsapp are read from the account by a bot while sms requires the person to text a short code from the number being proven, and no phone number is submitted. It does not elaborate on profile_id, client_metadata, or the context.action enum, leaving those to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb and resource ('Create a new phone verification session') and immediately names the returned artifacts (deep_link, qr_code, qr_text) plus the hosted-flow-with-callbacks model. It does not explicitly contrast itself with adjacent siblings such as create_verification, start_2fa, or create_multi_channel_verification, so an agent must infer the boundary from the word 'session'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit ordered workflow: create, hand deep_link to render_auth_link, then poll with wait_for_session until verified/failed/expired, and check validate_proof before relying on an SMS proof. It also states a prohibition ('Never hand qr_text to a link renderer') and the exact condition under which qr_text should be printed verbatim, which is the kind of when/when-not guidance that prevents misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_user_requestAInspect
Create a new verification request to ask another user to share verified assets. Each asset is an object naming its type, e.g. { "type": "email" }.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| assets | Yes | Assets to request, e.g. [{ "type": "email" }, { "type": "phone", "required": false }] | |
| partial_ok | No | Whether partial asset sharing is acceptable (default: false) | |
| action_type | No | Purpose of the request (default: verification); custom and confirmation also need an action_context title | |
| callback_url | No | HTTPS webhook URL for request status updates | |
| redirect_url | No | HTTPS URL to redirect the subject after completing the request | |
| reference_id | No | External reference ID for tracking | |
| action_context | No | What the recipient is shown about why the assets are needed, e.g. { "title": "Confirm your contact details" } | |
| expires_in_hours | No | Hours until request expires (default: 168, i.e. 7 days) | |
| public_profile_id | No | Public profile ID for branding | |
| validity_requirement | No | How recently an existing proof must have been verified for the recipient to reuse it: a number and a unit, h hours, d days, w weeks or m months (30 days), e.g. "24h", "7d", "1m" |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| assets | No | |
| status | No | Status of a verification request |
| progress | No | |
| created_at | No | |
| expires_at | No | |
| partial_ok | No | |
| updated_at | No | |
| action_type | No | Type of action for verification request or authorization |
| callback_url | No | The webhook URL set on the request, if any |
| completed_at | No | |
| redirect_url | No | |
| reference_id | No | |
| action_context | No | The action the person is asked to authorize; null when the request carries none |
| computed_state | No | Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces. |
| verification_url | No | URL for the verification flow |
| validity_requirement | No | Required proof freshness as set on the request (e.g. "7d"); null when none was set |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=false and destructiveHint=false, it discloses account and authentication requirements, the server-restart requirement, session-based access, and the need to call the tool again after signing in. It adds less about the resulting request's lifecycle or what happens after creation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, and the separate ACCESS paragraph makes setup and recovery steps easy to scan. The asset sentence is somewhat redundant with the richly documented schema, but the description remains compact and focused.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Together with the complete input schema, output schema, and safety annotations, the description provides enough purpose and access context for successful invocation. Its main remaining gap is selection context among near-duplicate creation siblings, particularly create_verification_request.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents the assets structure, allowed types, defaults, and constraints in detail. The minimal email-asset example is helpful but substantially repeats the schema's own description and example rather than adding new semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb, resource, and audience: creating a verification request that asks another user to share verified assets. It does not distinguish this tool from the especially close sibling create_verification_request or other creation tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description supplies concrete prerequisites and two actionable authentication paths: configure PROOF_API_KEY and restart, or use start_login and retry. It clearly establishes the sharing-request use case, but gives no guidance on when to prefer this tool over create_verification_request or related alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_verificationAInspect
Create a new identity verification. Initiates a verification flow for an asset identifier (phone number, email, domain, social handle, wallet address, account, or Telegram bot).
Agent usage: pass the asset type, the delivery channel, and the identifier (e.g. type "phone", channel "sms", identifier "+37060000000"; or type "email", channel "email", identifier "user@example.com"). The response carries a challenge object with the instruction for the chosen channel — except a telegram_bot verification made with a LIVE key, which the server completes on the spot and answers with status: verified plus a proof token and no challenge at all; with a pk_test_ key that same call stays pending and does carry a challenge. On the messenger channels it also carries challenge.deep_link — pass THAT to render_auth_link to give the user a clickable link and a QR code. This endpoint returns no qr_text at all. For OTP-based flows (sms/email), the user receives a code — poll get_verification or use wait_for_verification to track completion. For Telegram/WhatsApp, the user clicks the deep link to verify.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Asset type being verified | |
| channel | Yes | Verification channel (must match the asset type, e.g. sms/whatsapp/telegram for phone) | |
| bot_token | No | Telegram bot token (required for channel "telegram_bot_token") | |
| identifier | Yes | The asset identifier to verify (E.164 phone, email address, domain, handle, wallet address, ...) | |
| profile_id | No | The sub-account (24 hex characters) this is for; omitted, the key's own sub-account, else the primary. Its branding and templates are used for every message. | |
| dns_provider | No | DNS provider credentials (required for channel "auto") | |
| email_prefix | No | Mailbox prefix for domain email verification | |
| client_metadata | No | Custom key-value metadata | |
| external_user_id | No | Your application user ID for grouping verifications | |
| proof_expiry_days | No | Per-request proof expiry override in days (1-365) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| type | No | Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account. |
| proof | No | Proof token after successful verification |
| status | No | Current status of the verification |
| channel | No | Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken. |
| attempts | No | |
| challenge | No | Challenge details for verification |
| created_at | No | |
| identifier | No | The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it |
| updated_at | No | |
| verified_at | No | |
| max_attempts | No | |
| external_user_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the readOnly/destructive annotations: discloses that a telegram_bot call with a LIVE key completes immediately (status verified + proof token, no challenge) while pk_test_ stays pending, that no qr_text is returned, and that a PROOF_API_KEY must be set (start_login does not open it). Also warns that clients hide tool results, so the link/code must be surfaced in the agent's own reply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads what it does and the invocation recipe, then the response variants, then the access caveat. Dense but nearly every sentence carries actionable information; the live-vs-test key explanation is slightly repetitive.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, multi-channel creation tool with an output schema, this covers the invocation recipe, the divergent response shapes, downstream polling alternatives, and the auth prerequisite. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description adds value by pairing concrete examples ('type "phone", channel "sms", identifier "+37060000000"') that convey the type/channel matching constraint better than the schema's generic 'must match the asset type' note. It does not touch the optional params (profile_id, proof_expiry_days, client_metadata), relying on schema docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create a new identity verification') and enumerates the asset kinds it covers (phone, email, domain, social, wallet, account, Telegram bot). It never names the near-siblings create_verification_request or create_multi_channel_verification, so an agent must infer the boundary itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete routing: pass type/channel/identifier, then 'poll get_verification or use wait_for_verification' for OTP flows, and pass challenge.deep_link to render_auth_link. Lacks an explicit 'do not use this when...' exclusion against the many sibling verification tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_verification_requestAInspect
Create a multi-asset verification request. Allows verifying multiple assets (phone, email, domain, social, wallet, account, telegram_bot) in a single flow.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| assets | Yes | Array of assets to verify (1-10) | |
| expires_in | No | Request expiry in seconds (default: 604800, i.e. 7 days; max: 2592000, i.e. 30 days) | |
| partial_ok | No | Allow partial completion (default: false) | |
| action_type | No | Purpose of the verification (default: verification) | |
| callback_url | No | Webhook URL for status updates (HTTPS only) | |
| redirect_url | No | URL to redirect user after verification completes (HTTPS only) | |
| reference_id | No | Your unique reference ID for this request | |
| action_context | No | Context displayed to user during verification | |
| proof_expiry_days | No | Per-request proof expiry override in days (7, 30, 90, or 365) | |
| public_profile_id | No | Public profile ID for branding | |
| validity_requirement | No | How fresh an existing proof must be to count, as <n>h, <n>d, <n>w or <n>m (e.g. "7d") |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| assets | No | |
| status | No | Status of a verification request |
| progress | No | |
| created_at | No | |
| expires_at | No | |
| partial_ok | No | |
| updated_at | No | |
| action_type | No | Type of action for verification request or authorization |
| callback_url | No | The webhook URL set on the request, if any |
| completed_at | No | |
| redirect_url | No | |
| reference_id | No | |
| action_context | No | The action the person is asked to authorize; null when the request carries none |
| computed_state | No | Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces. |
| verification_url | No | URL for the verification flow |
| validity_requirement | No | Required proof freshness as set on the request (e.g. "7d"); null when none was set |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false, so the description's disclosure of an authentication/setup precondition that blocks invocation is valuable context beyond the schema. It stops short of explaining request lifecycle behavior (expiry, proof issuance, webhook firing), but the output schema covers the return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact paragraphs with the capability statement front-loaded and the access precondition isolated for easy scanning. No redundant filler, though the ACCESS block is slightly verbose for a single setup instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter nested tool the description is thin, but the schema is fully documented and an output schema exists, so the description's remaining duty is routing. It never distinguishes this tool from the many sibling creation/cancellation/status tools, which leaves ambiguity for a large toolset.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every one of the 11 parameters including the nested asset object is already documented in the schema. The description adds no syntax, defaults, or constraints beyond restating the asset-type list that is already the enum, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Create a multi-asset verification request') and enumerates the seven asset types it covers, so an agent knows exactly what the tool produces. It is not explicitly differentiated from close siblings like create_verification or create_multi_channel_verification, which is the main clarity gap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It supplies a real prerequisite ('needs a Proof account. Set PROOF_API_KEY and restart this server') and explicitly rules out a tempting but wrong path ('start_login does NOT open this tool'), which is genuine when-not guidance. It still doesn't say when to prefer this over the other request-creation siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_webhook_endpointAInspect
Add a webhook endpoint. An event reaches every active endpoint whose scope includes the event's sub-account and whose events match; an account-level event reaches "all"-scope endpoints only. An account still delivering to the single webhook URL in its settings is moved onto endpoints by this call (that URL becomes an "all"-scope endpoint with the same secret and events). The response carries the endpoint's signing secret — this and rotate_webhook_endpoint_secret are the only times it is returned, so store it now. Deliveries carry an HMAC-SHA256 X-Proof-Signature over "." made with it.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | HTTPS URL deliveries are sent to, at most 2000 characters. Private, loopback and link-local addresses are refused. | |
| scope | Yes | "all" serves every sub-account, present and future, plus account-level events; "selected" serves only the sub-accounts in profile_ids | |
| events | No | Subscription patterns (at most 32): an exact event type, a family wildcard such as "proof.*", or "*". An empty list means every event. | |
| status | No | A disabled endpoint receives nothing | |
| description | No | Your own label for the endpoint, at most 200 characters; null clears it | |
| profile_ids | No | Sub-account ids, 24 hex characters each, at most 100. At least one when scope is "selected"; none when scope is "all". |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| url | No | HTTPS URL deliveries are POSTed to, at most 2000 characters. Private, loopback and link-local addresses are refused. |
| scope | No | `all` — every sub-account, present and future, plus account-level events. `selected` — only the sub-accounts in `profile_ids`; account-level events never reach it. |
| events | No | |
| legacy | No | The endpoint converted from the account's single webhook URL — the one the deprecated `/me/settings` webhook block reads and writes. |
| secret | No | The signing secret — returned only in this response. Store it now. |
| status | No | A `disabled` endpoint receives nothing; its history and secret are kept. |
| created_at | No | |
| secret_set | No | Whether the endpoint has a signing secret (always true). |
| updated_at | No | |
| description | No | |
| profile_ids | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and destructiveHint=false, and the description adds substantial behavior beyond them: the side effect of moving a legacy settings URL onto an 'all'-scope endpoint with the same secret, and the one-time disclosure of the signing secret. However, the closing paragraph discloses a hard access prerequisite (PROOF_API_KEY must be set and the server restarted) that is not captured by any annotation and would block every call until satisfied — that materially changes the tool's operability and warrants flagging rather than full credit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then routing semantics, then the secret-handling warning, then access. Sentences are dense but each carries information; the HMAC signature format is useful but slightly tangential to the create operation itself.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values needn't be enumerated, yet the description correctly highlights the one return detail that matters operationally — the signing secret is shown only here and via rotate_webhook_endpoint_secret. Combined with routing rules and access prerequisites, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so scope, events, status and profile_ids are already well documented with enums and constraints. The description reinforces the meaning of scope ('all' vs sub-account coverage) and event matching, but adds little per-parameter detail beyond the schema baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ('Add a webhook endpoint') and immediately distinguishes itself from the sibling update/list/delete endpoint tools by describing creation semantics and delivery routing. The agent can tell what is being created and what it affects without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit context for when this fires: an event reaches every active endpoint whose scope includes the sub-account, account-level events reach only 'all'-scope endpoints, and legacy single-URL accounts are migrated by this call. It also names the alternative ('rotate_webhook_endpoint_secret') for retrieving the secret again and explicitly rules out an adjacent tool ('start_login does NOT open this tool'), which is exactly the kind of exclusion an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_circleADestructiveInspect
Archive a Circle (soft delete — sets status to archived). It stops appearing in the default list but is recoverable via list_circles with status="archived".
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID to archive |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructiveHint=true, which would suggest irreversible data loss; the description corrects that impression by disclosing the operation is a recoverable archive and specifying the recovery path. It also discloses a real operational prerequisite (Proof account, PROOF_API_KEY, server restart) and explicitly rules out start_login as a workaround, which is exactly the kind of context an agent cannot get from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, each front-loaded with its most important fact: the soft-delete semantics first, then the access requirement. No redundant restatement of the title or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter mutation with an output schema and annotations, everything an agent needs is present: what the state change is, that it is recoverable, how to find archived items, and how to obtain credentials. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter already documents the 24-hex-char format and its meaning. The description adds no additional semantics about the id beyond what the schema states, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Archive a Circle") and immediately disambiguates the ambiguous name by clarifying it is a soft delete that sets status to archived, not a hard removal. This distinguishes it clearly from get_circle, update_circle, and list_circles.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the observable effect (disappears from the default list) and names the exact recovery route (list_circles with status="archived"), which effectively tells an agent when the action is safe and how to undo it. It does not explicitly compare against update_circle for status changes, but the routing is clear in practice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_dns_credentialADestructiveInspect
Delete a stored DNS provider credential. Domains using this credential will need new credentials for automated verification.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | DNS credential ID to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, and the description goes beyond that by disclosing the downstream effect on domain verification and the auth prerequisite (PROOF_API_KEY or a start_login session). It stops short of saying whether deletion is reversible or what happens if the ID is unknown, which for a destructive operation would be valuable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and its consequence are front-loaded in two tight sentences, which is exactly right. The trailing access instructions are necessary but syntactically dense, stacking a restart path, a login path, and a retry step into one sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with full schema coverage, annotations, and an output schema, the description covers the essential concerns: impact on dependent domains and authentication requirements. Missing only edge-case behaviour, such as errors for nonexistent IDs or whether the deletion can be undone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter exists and its schema description ("DNS credential ID to delete") already covers it at 100% coverage, so the baseline of 3 applies. The prose adds no format, source, or lookup guidance for the id beyond what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb plus resource, "Delete a stored DNS provider credential," which clearly separates it from create_dns_credential and list_dns_credentials. It never names a sibling or explicitly contrasts itself with neighbouring deletion tools such as delete_domain, so it sits just short of full differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: an agent can infer this is for removing a credential that is no longer needed, and the second sentence warns about consequences for domains relying on it. There is no explicit when-to-use or when-to-avoid guidance, and no named alternative for replacing a credential instead of deleting it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_domainADestructiveInspect
Remove a domain from the account. Revokes every proof of the domain and every delegation issued from it (for good — re-adding the domain does not bring them back), deletes the domain and its records, and removes our _proof TXT record and the Resend sending domain where we can; the response lists what is left for you to remove by hand. Owner only, in a start_login session, with one code: start_2fa_for_action with action_type domain_remove and targets [this domain id]. Need only a fresh proof? Revoke the proofs instead (revoke_asset), which keeps the domain. Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
| domain | No | |
| notice | No | |
| success | No | Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major. |
| carriers | No | Where the revoked delegations are still published (the `_mcp.<domain>` pointer, a delegate card) — bounded to a few delegations and a few seconds. |
| external | No | |
| proofs_revoked | No | |
| delegations_revoked | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructive annotation, the description discloses the full cascade: proofs and delegations are permanently revoked, the domain and records are deleted, the _proof TXT record and Resend sending domain are removed where possible, and the response lists manual cleanup. It also states irreversibility and the exact authorization flow.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the action and consequences, then moves to the alternative, authorization requirements, and irreversibility. Every sentence carries operational value; none is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a destructive cascade tool with one parameter and an output schema. The description covers consequences, manual follow-up, authorization, alternative behavior, and irreversibility, so it is complete for correct selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the single id parameter is already documented as 'Domain ID to delete.' The description adds only that the id is the target of the 2FA action, without format or validation details. A baseline of 3 is appropriate when the schema carries parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Remove a domain from the account.' It then distinguishes the operation from the narrower alternative by stating that revoke_asset should be used when only proofs need revoking. An agent can identify this as the destructive domain-removal tool without inspecting siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use and when-not-to-use guidance, including the alternative 'revoke_asset' for proof-only revocation. It also states prerequisites: owner only, start_login session, and start_2fa_for_action with action_type domain_remove and the domain id.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_domain_verificationADestructiveInspect
Delete a domain verification attempt that is not verified (pending, verifying or failed) — nothing is revoked. A verified domain, or one that needs re-verification, is refused with domain_verified: removing it revokes its proofs and every delegation issued from it, which is delete_domain in a start_login session (or the dashboard).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain verification ID (24 hex characters) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The id of the deleted domain verification |
| deleted | Yes | The domain verification was deleted |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the destructiveHint=true annotation by disclosing that nothing is actually revoked, naming the exact refusal signal (domain_verified), and describing the side effects that the alternative (delete_domain) would trigger — proofs and all delegations. Auth prerequisites (PROOF_API_KEY, server restart) are spelled out. Missing only from annotations' perspective: irreversibility of the delete and behavior on an unknown ID.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and its constraint, and the ACCESS block is clearly separated. However, the clause 'which is delete_domain in a start_login session (or the dashboard)' is dense and hard to parse on first read, costing some clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter delete tool with an output schema and covering annotations, the definition supplies the refusal path, side effects, the alternative tool, and the auth gate. Return values are handled by the output schema, so nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (single 'id' with a 24-hex pattern), so the schema already carries the format constraint. The description only implies the ID identifies a verification attempt rather than a domain, which is marginal added meaning; baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete a domain verification attempt') and immediately bounds the scope to non-verified attempts via the enumerated statuses pending/verifying/failed. It explicitly distinguishes itself from delete_domain, so an agent can choose between them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives both when-to-use and when-not: unverified attempts can be deleted, verified or re-verification-pending domains are refused with a named error (domain_verified), and the correct alternative (delete_domain) is named for that case. The ACCESS paragraph further states the tool is unavailable in a start_login session, which is an unusual but important exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_hitlADestructiveInspect
Delete (archive) a HITL config. Sets status to archived. Cannot be used for new confirmations after deletion.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | HITL config ID to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | No | |
| status | Yes | Status of a HITL configuration |
| keypair | Yes | Encryption keypair metadata (null if not configured) |
| user_id | Yes | Owner user ID (useful for SDK encryption AAD) |
| channels | Yes | |
| circle_id | No | Backing Circle for a circle-backed Approvals config (null for channel-list configs) |
| created_at | Yes | |
| profile_id | No | |
| updated_at | Yes | |
| environment | Yes | |
| timeout_seconds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the bar is lower, but the description still adds real value: it discloses that the operation is a soft delete (archive) rather than a hard purge, and quantifies the downstream effect on new confirmations. The authentication/restart requirement is also disclosed, which annotations cannot convey. It does not say whether an archived config can be restored or re-activated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded in the first two sentences, and the access caveat is separated into its own block, which is easy to scan. The access paragraph is somewhat verbose for a single repeated environmental prerequisite, but it earns its place by preventing a predictable authorization failure loop.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with annotations covering the safety profile and an output schema covering the response, the description covers purpose, effect, and prerequisites adequately. The remaining gap is recoverability — whether an archived config can be restored — which matters for a destructiveHint=true tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (id) and schema description coverage is 100%, so the schema already fully documents it. The description adds no format, sourcing, or lookup guidance for the ID beyond what the schema states, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete (archive) a HITL config') and immediately disambiguates the semantics of that verb by clarifying it is an archive that sets status to archived. Among siblings named delete_* (delete_domain, delete_template, delete_hitl_keys, delete_circle), the HITL-config scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the operative condition an agent needs: after deletion the config cannot be used for new confirmations, which tells the agent this is a prerequisite-breaking action. It also states the access precondition (Proof account, PROOF_API_KEY, restart) and explicitly warns that start_login does NOT unlock this tool. It stops short of naming an alternative such as update_hitl or the list/get siblings for inspection-before-delete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_hitl_keysADestructiveInspect
Delete the encryption keypair from a HITL config. WARNING: Existing ciphertexts will become permanently unreadable.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| hitl_id | Yes | HITL config ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already flag destructiveHint=true, but the description adds a concrete consequence those annotations cannot express: existing ciphertexts become permanently unreadable. It also discloses a real access precondition (a Proof account with PROOF_API_KEY set, server restart, and no start_login path), which is exactly the kind of operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose comes first, then the destructive warning, then the access requirement, so severity is front-loaded and each block carries distinct information. The ACCESS paragraph is a little telegraphic ('start_login does NOT open this tool'), but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description covers the destructive outcome and the authentication prerequisite. The one gap is whether the keypair can be restored afterwards via upload_hitl_keys, which would tell the agent how reversible this really is.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter, hitl_id, and schema description coverage is 100%, so the schema already supplies its meaning ('HITL config ID'). The description adds nothing about parameter formatting or sourcing, which is acceptable given full schema coverage but earns no extra credit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Delete the encryption keypair from a HITL config'), which cleanly separates it from sibling key tools such as get_hitl_keys and upload_hitl_keys as well as from delete_hitl, which deletes a config. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The warning about existing ciphertexts becoming permanently unreadable makes the condition that should trigger caution explicit, and the ACCESS note tells the agent that the tool cannot be unlocked via start_login. It stops short of naming concrete alternatives (for example, whether to re-upload keys via upload_hitl_keys instead of deleting), so it is clear but not fully comparative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_profileADestructiveInspect
Delete a sub-account (profile). Revokes its API keys, archives the HITL setups and declines the pending requests created with its own keys, keeps its history but unlinks it, deletes its message templates, and retires its username for good. The last sub-account cannot be deleted; deleting the primary sub-account makes the oldest remaining one primary (the response names it). In a start_login session: one code first — start_2fa_for_action with action_type profile_delete and targets [this sub-account id]. With an API key alone only an EMPTY sub-account (no API keys, HITL setups or pending requests) can be deleted; anything else answers owner_session_required. archive_default_linked is deliberately not offered here: archiving or cancelling everything linked only by default is an irreversible fan-out, so archive each item explicitly instead. Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | Yes | Profile ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| project | No | |
| success | No | Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major. |
| new_primary | No | Named when the deleted sub-account is (or was) the primary: the OLDEST remaining sub-account takes over, and messages sent without choosing a sub-account carry its name. |
| was_primary | No | |
| hitl_archived | No | |
| hitl_detached | No | |
| api_keys_revoked | No | |
| circles_detached | No | |
| domains_detached | No | |
| username_retired | No | The username is retired for good — it can never be claimed again, by anyone. |
| requests_detached | No | |
| templates_deleted | No | |
| requests_cancelled | No | |
| confirmations_denied | No | |
| authorizations_revoked | No | |
| verifications_detached | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructiveHint=true; the description goes well beyond by spelling out every side effect (what is revoked, archived, declined, unlinked, and what is permanently destroyed - templates and the username), that the operation is irreversible, and the side effect of promoting the oldest remaining sub-account to primary (with the response naming it). Auth paths are covered (PROOF_API_KEY, start_login session, API key with empty-account restriction). It stops short of describing the response body, but an output schema exists so that is largely covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and its consequences, then prerequisites, then auth. Dense but nearly every sentence carries operative information; the only mild redundancy is "Cannot be undone" at the end, which restates destructiveHint, and the access note is longer than strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter but high-blast-radius destructive tool, the definition covers side effects, irreversibility, prerequisite 2FA, error conditions, primary reassignment behavior, and authentication options. With an output schema present and naming the new primary, the description need not enumerate return fields.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single profile_id parameter, so the baseline would be 3. The description adds genuine meaning beyond the schema by tying the id to a downstream flow: it must be passed as targets [this sub-account id] to start_2fa_for_action when deleting inside a start_login session, which the schema's bare "Profile ID" does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: "Delete a sub-account (profile)." It immediately enumerates the concrete effects (revokes API keys, archives HITL setups, declines pending requests, deletes message templates, retires username), which clearly separates it from create_profile, update_profile, set_primary_profile, and delete_hitl among the many siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-can/cannot rules: the last sub-account cannot be deleted, an API-key-only caller may delete only an EMPTY sub-account, and it names the exact error (owner_session_required). It also routes the agent to a specific prerequisite sibling (start_2fa_for_action with action_type profile_delete) and explicitly explains why an alternative option (archive_default_linked) is deliberately not offered, telling the agent to archive items individually instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_templateADestructiveInspect
Delete a sub-account's custom template, reverting that sub-account to the default template for the channel and message type.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Message channel | |
| profile_id | No | The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key | |
| message_type | Yes | Message type (e.g. verification_request, login_request) |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, but the description adds the non-obvious consequence: the sub-account falls back to the channel/message-type default template. The auth/restart requirement is also disclosed, which the annotations do not cover. It stops short of saying whether the custom template content can be recovered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, the core action and its effect front-loaded, with the access caveat second. No filler and no redundancy with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists so return values need not be explained, and the destructive nature plus the post-delete state is covered. The remaining gap is reversibility of the deleted custom template, which matters for a destructive operation but is minor given the rich schema and annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents channel (enum), message_type, and profile_id with its fallback behavior. The description only restates that channel and message type scope the default reversion and that the target is a sub-account; it adds little beyond the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete a sub-account's custom template') and, crucially, the resulting state change ('reverting that sub-account to the default template for the channel and message type'). An agent can distinguish this from update_template or get_default_templates, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The access note gives a concrete prerequisite (needs a Proof account, set PROOF_API_KEY and restart) and explicitly rules out an alternative path ('start_login does NOT open this tool'), which prevents a likely dead end. It does not state when to prefer update_template over deleting, so no full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_webhook_endpointADestructiveInspect
Delete a webhook endpoint. It receives no new events; deliveries already queued to it are still attempted, signed with the secret they were queued with. Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook endpoint ID |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, yet the description adds genuinely non-obvious behavior: queued deliveries are still attempted and are signed with the secret they were queued with, plus irreversibility. The access/authentication block is exactly the kind of operational context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The behavioral consequences are front-loaded ahead of the access instructions, and each sentence carries distinct information (scope, queued deliveries, irreversibility, auth). The ACCESS block is slightly long relative to the core operation but is not padding, since each clause is actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter destructive tool with an output schema and full annotation coverage, the description supplies everything the agent needs: the effect on future events, the fate of in-flight deliveries, irreversibility, and the authentication gate. Nothing material is left for the agent to infer before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter (id) with 100% schema description coverage and a 24-hex-character pattern documented in the schema, so the schema already carries parameter meaning. The description adds no id sourcing or format detail beyond it, which is the baseline case for a fully covered single-parameter schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ("Delete a webhook endpoint") and immediately scopes the consequence ("It receives no new events"), which clearly separates it from siblings such as update_webhook_endpoint or rotate_webhook_endpoint_secret. An agent can identify the operation and its effect without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for when this applies and, importantly, a hard prerequisite for use (needs a Proof account, PROOF_API_KEY set, server restarted) plus an explicit dead end ("start_login does NOT open this tool"). It stops short of naming alternatives, e.g. whether updating the endpoint to disable it is a non-destructive option, so it is not a full when/when-not treatment.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_authorizationsARead-onlyInspect
Export authorizations as CSV or JSON. Supports date range and status filtering. Maximum 10,000 records.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | End date filter (ISO 8601) | |
| from | No | Start date filter (ISO 8601) | |
| format | No | Export format (default: json) | |
| status | No | Filter by status |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| total | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true, and the description adds important operational details beyond that: a Proof account is required, PROOF_API_KEY must be set with a server restart, start_login is insufficient, and exports are capped at 10,000 records. It does not describe truncation behavior when the cap is reached, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core export capability, followed by a compact access note. Every sentence adds actionable information without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an export tool with an output schema and fully documented parameters, the description covers capability, filters, formats, record limit, and authentication prerequisites. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including enum values for format and status, so the schema already carries parameter meaning. The description reinforces date range and status filtering but adds no syntax or format details beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — export authorizations — plus supported formats and filtering scope. It clearly distinguishes exporting from sibling listing tools like list_authorizations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context: export as CSV or JSON with optional date-range and status filters, capped at 10,000 records. It does not explicitly name alternatives or when not to use this tool, but the export framing is sufficiently clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_dataAInspect
Export a complete copy of your account's data (GDPR Articles 15 and 20), or check on one. Owner only: sign in with start_login first (a connection with only an API key is refused user_session_required). The first call starts the export; it is prepared in the background, and the account owner is told by email (or on their login channel) with a link that downloads it only while they are signed in — this tool never returns the data itself. Call again to see whether it is ready: an export already preparing or ready is reported instead of starting another. One new export per 24 hours (no limit while the account is scheduled for deletion); the file is kept for 7 days. Pass export_id to read one export's status.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| export_id | No | Read this export's status instead of the latest one |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| error | No | `too_large` — more than one download can carry (no partial file is ever produced; contact support); `internal` — a failure on our side (start a new export at once, the daily limit was given back) |
| counts | No | Rows per section of the file |
| latest | No | |
| status | No | `preparing` while the job runs; `ready` once the file can be downloaded; `failed` with `error` |
| ready_at | No | |
| receipts | No | Receipts of the account's downloads, newest first (the latest 20) |
| expires_at | No | The export and its file are deleted at this time — 7 days after the request |
| size_bytes | No | Size of the compressed file as stored |
| requested_at | No | |
| download_path | No | Path of the download route while `ready`, else null |
| downloaded_at | No | The first download, if any |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, destructiveHint=false): the tool never returns the data itself, delivery is by email/login-channel link, results require an active session, an in-flight export is reported instead of a duplicate, and quotas (one per 24h, 7-day retention, no limit during deletion) are spelled out.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded and the sentences mostly earn their place, but the trailing ACCESS paragraph restates the earlier 'sign in with start_login first' requirement, adding redundancy to an already long description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an asynchronous, auth-gated, quota-limited export job, everything needed to invoke it correctly is present: prerequisites, polling pattern, rate limits, retention, and the fact that no data is returned inline (an output schema also exists).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the export_id description ('Read this export's status instead of the latest one') already carries nearly all the meaning. The description's 'Pass export_id to read one export's status' largely restates the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Export a complete copy of your account's data') and immediately covers the dual mode ('or check on one'), which separates it from the many verification/export_authorizations siblings. An agent can tell exactly what this tool produces without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use and how: first call starts the export, call again to check readiness, pass export_id to read a specific one. It also names the required prerequisite (owner must sign in via start_login) and the alternative path (API key alone is refused with user_session_required).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extend_requestBInspect
Extend the expiration time of a pending verification request.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification request ID to extend | |
| extends_by_hours | No | Hours from now until the request expires, 1–720 (default: 168, i.e. 7 days). An expired request is reactivated. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | Status of a verification request |
| message | Yes | `Verification request extended`, or `Verification request reactivated and extended` for a request that had expired (its `status` is then `pending` or `partial` again) |
| success | Yes | |
| expires_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations mark this as a non-read-only but non-destructive mutation, and the description is consistent with that while adding genuine value: the Proof account requirement and how to satisfy it (PROOF_API_KEY or start_login). It stops short of saying whether extension is idempotent, whether it affects proof validity or delivery state, or what happens on repeated calls, which matters for a mutation with only two annotation hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in one clean sentence, but the ACCESS block is nearly as long as the purpose and contains awkward phrasing ('a session opens this tool') plus server-restart instructions. It earns partial credit for being actionable, but it is not tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, the two parameters are fully documented, and the authentication prerequisite is spelled out. The only real gap is behavioral detail about the effect of extending on surrounding request state, which is minor for a straightforward two-parameter mutation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both parameters are already documented in the schema, including the 1–720 range, the 168-hour default, and the fact that an expired request is reactivated. The description adds no parameter-level meaning beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Extend the expiration time of a pending verification request.' An agent can tell it apart from cancel_verification_request or get_verification_request by the verb alone. It does not, however, name any sibling alternative, so the differentiation is implicit rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: you extend when a pending request needs more time. The description never contrasts this with cancelling the request or creating a new one, which are the realistic alternatives among the many sibling verification tools. The access/reset instructions are prerequisites rather than when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_2fa_statusARead-onlyInspect
Check the status of a 2FA session by session ID. Returns whether the challenge has been completed, is pending, or has expired.
Agent usage: Poll this after calling start_2fa. Check every few seconds. Terminal states: "verified" (proceed with protected operation), "expired" (restart with start_2fa). While "pending", the user has not yet entered their code.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | 2FA session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | |
| session_id | Yes | |
| action_type | Yes | The action the session was started for: one of `TwoFAActionType` for sessions started through this API; admin-console sessions carry internal values. |
| verified_at | No | |
| grant_expires_at | No | When the grant this step-up stored stops being accepted |
| grant_single_use | No | Whether the grant is spent by the first act it allows |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnlyHint; the description adds real behavioral context: the three-state lifecycle, what each terminal state implies for downstream work, and the non-obvious requirement that the challenge link/SMS text be surfaced in the reply text before polling. It does not mention timeouts or rate limits, so it stops short of fully transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and state enumeration, then a clearly labeled "Agent usage" block and an access/auth note. The access paragraph is somewhat tacked on but is short and operationally relevant; no sentence is pure filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not detail return shape, and it still covers lifecycle semantics, polling cadence, and auth prerequisites. The only meaningful hole is not contrasting itself with wait_for_2fa for agents that prefer a blocking call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter (session_id) is already documented. The description only restates "by session ID" and adds no format, sourcing, or validation detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Check the status of a 2FA session by session ID" states a specific verb and resource, and the next sentence enumerates the exact return states (completed/pending/expired). An agent can immediately distinguish this read-only status check from verify_2fa or wait_for_2fa.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to poll after start_2fa, gives a cadence ("every few seconds"), and maps terminal states to next actions (proceed vs. restart with start_2fa). It omits the polling sibling wait_for_2fa, which is a plausible alternative for the same job.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_add_email_statusARead-onlyInspect
Check the status of an in-progress email addition by session ID.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Add-email session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| Yes | ||
| status | Yes | |
| channel | Yes | |
| session_id | Yes | |
| verified_at | No | Present once `status` is `verified` |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, which matches the read-only polling nature of the tool, so there is no contradiction. The description adds genuinely useful context beyond that: it requires a Proof account, may need PROOF_API_KEY plus a server restart, or a start_login session before the call will succeed. That authentication/setup disclosure is exactly the kind of behavioral detail annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded statements: the purpose first, then the access prerequisite. Nothing is wasted, though the parenthetical 'a session opens this tool' is slightly ambiguous about whether it refers to an auth session or an add-email session.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple, has one documented parameter, an output schema covering return values, and readOnlyHint annotations covering safety. The description closes the remaining gap by explaining the authentication prerequisite, so an agent knows everything needed to invoke it successfully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter, session_id, and the schema already documents it at 100% coverage as 'Add-email session ID'. The description restates 'by session ID' without adding format, origin, or lifetime details, so this is the baseline case where the schema does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: 'Check the status of an in-progress email addition by session ID.' That clearly separates it from mutation siblings such as start_add_email or remove_email, and from check_domain_email_status by the 'email addition' scope. It stops short of naming its counterpart (start_add_email) explicitly, so it is clear but not maximally differentiating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'in-progress email addition' implies this is a follow-up poll after starting an add-email flow, and the ACCESS block states the prerequisite of a Proof account. However, no alternative tool is named and there is no explicit when-not-to-use guidance (for example, vs. get_add_phone_status or check_domain_email_status), so usage is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_add_phone_statusARead-onlyInspect
Check the status of an in-progress phone addition by session ID. Poll until terminal state.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Add-phone session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | |
| channel | Yes | |
| session_id | Yes | |
| verified_at | No | Present once `status` is `verified` |
| phone_number | No | The number the person proved; absent until they have |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true is consistent with a status check, and the description adds behavior the annotation cannot express: the operation is asynchronous and expected to be polled, and there is a user-facing side effect if the challenge details never left the tool result. The ACCESS block discloses the PROOF_API_KEY prerequisite and the start_login fallback for opening a session, which is genuinely useful operational context. What is missing is any statement about how long sessions persist or which states count as terminal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short blocks, each with a distinct job: what it does, the user-visible precondition, and the auth requirement. The polling instruction is front-loaded in the opening sentence. The middle paragraph is somewhat lengthy for a caveat, but it is the highest-risk failure mode so it earns the space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description correctly does not spend words on return values, and the readOnly annotation covers the safety profile. It fills the gaps that structured fields cannot express: async polling, auth setup, and the requirement to surface challenge details to the human. Only the definition of terminal states and any timeout behavior remain unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single session_id parameter, and the description's phrase 'in-progress phone addition by session ID' adds only the qualifier that the ID comes from an add-phone flow. That is a marginal gain over the schema's own 'Add-phone session ID' text. With the schema fully documented, the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb and resource: 'Check the status of an in-progress phone addition by session ID.' That is enough to separate it from start_add_phone (which initiates), list_phones (which enumerates), and get_add_email_status (which covers email rather than phone). It stops short of naming any of those siblings, so an agent has to infer the boundaries instead of being told them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Poll until terminal state' tells the agent how the tool is meant to be driven, which is real usage guidance rather than a restatement of purpose. The paragraph about putting the link, SMS text, or inbox note in the reply before calling is a concrete when-to-use condition tied to user-visible outcomes. It never states an alternative (e.g. a wait/poll helper) or what to do on a non-terminal state other than keep polling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_api_key_usageARead-onlyInspect
Get per-API-key usage for a given key id: verification counts by type/channel/status, plus verification-request/confirmation/authorization totals, and attribution context (attribution_cutoff_at, attributed_fraction). The counts cover the key and every key it replaced (api_key.replaced_key_ids). Counts only — no recipient identifiers. Scoped to the authenticated account; an API-key caller may read only its own key.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The API key id to fetch usage for | |
| environment | No | Scope metrics to test or production data (default: production) |
Output Schema
| Name | Required | Description |
|---|---|---|
| api_key | Yes | |
| confirmations | Yes | |
| verifications | Yes | |
| authorizations | Yes | |
| attributed_fraction | Yes | Fraction of the user verifications linked to any API key in scope (null when there are none) |
| attribution_cutoff_at | Yes | UTC-day-floored date attribution began for this user (earliest key-linked verification), or null |
| verification_requests | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses non-obvious behavior an agent could not infer: counts roll up the key plus all keys it replaced via replaced_key_ids, results are aggregate-only with no recipient identifiers, and authorization limits differ between session and API-key callers. Those are exactly the traits that affect whether and how the tool should be called.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and return contents are front-loaded in the first sentence, followed by scope caveats and a clearly separated ACCESS block. It is information-dense without padding, though the comma-heavy enumeration and the duplicated access/session note add some length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, two-parameter tool with a full schema, an output schema, and annotations, the description covers what is missing: aggregation semantics, privacy limits, and authentication prerequisites. An agent has everything needed to call it correctly without guessing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented in the schema, which sets the baseline at 3. The description clarifies that 'id' is expanded to include replaced keys (a semantic detail the schema omits), but never mentions the environment parameter or its production/test defaulting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get per-API-key usage for a given key id') and then enumerates exactly what the response contains (verification counts by type/channel/status, request/confirmation/authorization totals, attribution context). The scoping sentence ('counts cover the key and every key it replaced') further pins down what 'per-key' means, so an agent can distinguish this from account-wide siblings like get_usage.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: it applies to a specific key id, is scoped to the authenticated account, and an API-key caller can only read its own key — plus an explicit ACCESS block telling the agent to set PROOF_API_KEY or run start_login first. It stops short of naming the obvious alternative (get_usage) as the choice for account-level aggregates, so the routing decision is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_assetARead-onlyInspect
Get a single verified asset by ID. Returns details including type, value, status, and verification timestamps.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Asset ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| type | Yes | Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account. |
| status | Yes | Status of a verified asset |
| channel | Yes | How the asset was verified: a verification channel, or `otp` / `magic_link` for an email address confirmed from the dashboard |
| metadata | No | Channel-specific details recorded at verification |
| proof_id | No | Public handle of the proof backing this asset (`ph_ctl_<32 hex>`), or null when the asset predates the proof registry. This is the `control_proof` value `POST /api/v1/delegations` takes. |
| has_proof | No | Whether a proof token is stored for this asset. Sent by the point read (`GET /me/assets/{id}`) only. |
| created_at | Yes | |
| identifier | Yes | |
| proof_token | No | The stored signed proof token. Returned by the point read (`GET /me/assets/{id}`) to a JWT owner session ONLY — an API-key caller and the list response carry `has_proof` alone. |
| verified_at | No | |
| proof_status | No | Registry status of that proof. Only an `active` proof can anchor a delegation. |
| proof_expires_at | Yes | When the proof backing this asset expires |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered by structured data. The description adds genuinely new behavior: the authentication prerequisite, the restart requirement, and the fact that start_login is not a path to access this tool — context an agent could not get from the schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight blocks: the purpose and return fields first, then a clearly separated ACCESS section. No filler sentences; the access note earns its space because it prevents a failed call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool with an output schema and readOnlyHint annotation, the description covers purpose, return shape at a high level, and access preconditions. The only gap is sibling differentiation against list_assets, which is minor given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With a single parameter at 100% schema description coverage, the schema already defines 'id' as the asset ID. The description adds only the qualifier that the asset is 'verified' and is looked up 'by ID', which is marginal meaning beyond the schema — baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get a single verified asset by ID') and names the returned fields (type, value, status, verification timestamps). 'Single' implicitly contrasts with the sibling list_assets, though that sibling is never named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is real guidance in the ACCESS block: it states the tool requires a Proof account with PROOF_API_KEY set, and explicitly warns that start_login does NOT open this tool, which prevents a common misrouting. However, it never says when to prefer this over list_assets or get_profile_assets for asset lookup, so alternative selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_authorizationARead-onlyInspect
Get an authorization by ID. Returns the current state of the authorization including status and usage statistics.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Authorization ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bsuid | No | WhatsApp Business-Scoped User ID |
| label | No | Owner-assigned human label for this approver (F22); null when unset. Surfaces lead with it, falling back to the masked recipient. |
| phone | No | |
| scope | Yes | Scope of the authorization. `identity_challenge` is the Proof of Me scope. |
| status | Yes | Status of an authorization |
| channel | Yes | Channel authorized for sending confirmations |
| hitl_id | No | |
| enrolled | Yes | Whether the approver has enrolled an encryption key. A confirmation can be sealed to an approver only once this is true; consent alone (`status: active`) is not enough. |
| circle_id | No | |
| denied_at | No | When the recipient refused — the mirror of `authorized_at` for a `denied` row (a challenger cancellation stamps it too). Absent unless the authorization was denied; before it existed such a row carried no decision time at all, only `updated_at`. |
| recipient | No | Channel-specific recipient identifier (chat_id for Telegram, phone or BSUID for WhatsApp) |
| created_at | Yes | |
| expires_at | Yes | |
| revoked_at | No | |
| updated_at | Yes | |
| proof_token | No | Signed proof of the recipient's decision, minted when they approved or refused, for both scopes. Absent while no decision has been made. |
| last_used_at | No | |
| authorized_at | No | |
| business_name | Yes | |
| verification_id | No | MongoDB ObjectId |
| revocation_reason | No | |
| confirmations_sent | Yes | |
| recipient_display_name | Yes | The approver's own messenger name ("First Last @username"), captured when they approved over Telegram; null when none was captured. Chosen by the approver, not verified. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true is consistent with the read semantics. Beyond the annotation, the description discloses the authorization prerequisite and the configuration step needed before the call can succeed, which annotations cannot convey, plus a hint at payload contents (status, usage statistics). The only gap is that the output schema already covers return shape, so nothing further is added there.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded in one short sentence, followed by a clearly separated ACCESS block that is actionable rather than filler. The restart instruction is slightly operational and verbose, but it earns its place because the call fails without it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema and readOnlyHint already documenting the return value and safety profile, the description only needed to add the access prerequisite, which it does explicitly. For a one-parameter read tool this is essentially complete, barring a pointer to the listing alternative.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter with 100% schema description coverage ('Authorization ID'), so the schema already carries the parameter meaning. The description adds no format, prefix, or sourcing detail for the ID, leaving the schema to do all the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Get an authorization by ID') and states the returned data (status and usage statistics), so the operation is unambiguous. It does not distinguish itself from nearby siblings such as list_authorizations or revoke_authorization, but the single-item lookup is self-evident from the name and text.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS paragraph tells the agent a precondition (Proof account, PROOF_API_KEY set, server restart) and explicitly warns that start_login does not unlock this tool. That is useful eligibility guidance, but there is no statement of when to pick this over list_authorizations or get_request_proofs, so usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_balanceARead-onlyInspect
Get the prepaid balance (in euro cents and mills), the low-balance threshold, the top-up amounts on offer and the auto top-up setting. Proofs past the plan's included amount are drawn from this balance; once billing is live, an account whose balance is at or below zero is refused new proof requests (402 balance_empty) until it tops up. billing_enabled says whether billing is live. Topping up and changing auto top-up are done by the owner in the dashboard.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| balance | Yes | |
| auto_top_up | Yes | |
| top_up_amounts | Yes | The top-up amounts on offer, in euros. |
| billing_enabled | Yes | Whether billing is live. While it is off, nothing is drawn from the balance and nothing is paused. |
| low_balance_threshold | Yes | The balance in euro cents below which the owner is sent a low-balance notice. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses the currency units, the billing model (proofs past the included plan amount draw from this balance), the failure mode (402 balance_empty when balance is at or below zero), the meaning of billing_enabled, and the exact auth remedy including that start_login will not unlock this tool. This is substantial behavioral context that annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then billing consequences, then a clearly separated ACCESS block. Dense but nearly every clause carries information; the sentence about topping up being dashboard-only could arguably be folded into the access paragraph.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, yet the description still pre-empts the key questions: units, what the balance gates, the error condition, and the prerequisite to call it at all. Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so there is nothing to disambiguate; the baseline applies. The description still adds value by naming the units (euro cents and mills) of the primary returned quantity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Get the prepaid balance') and enumerates the returned fields: balance in euro cents and mills, low-balance threshold, top-up amounts, auto top-up setting. It is clearly distinguishable from list_balance_ledger and get_subscription in substance, but it never names those siblings or explains the boundary explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operating context: what consumes the balance, when requests get refused (402 balance_empty), and explicitly rules out top-up/auto-top-up changes ('done by the owner in the dashboard'), which prevents a wasted call. The access prerequisite block is unusually actionable, though it does not say when to prefer this over get_usage or list_balance_ledger.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_circleARead-onlyInspect
Get a Circle by ID. Returns the Circle including its members and per-member channel presence booleans (an identifier is NEVER returned — SEC-PM-006).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | Yes | |
| status | Yes | Lifecycle state of a Circle (archived = soft-retired) |
| members | Yes | |
| user_id | Yes | |
| created_at | Yes | |
| owner_name | Yes | How this Circle's members know its owner; null when unset |
| profile_id | Yes | |
| updated_at | Yes | |
| environment | Yes | |
| member_count | Yes | |
| proof_me_enabled | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true is already supplied, so the safety profile is free; the description goes further by disclosing the return shape (members and their per-channel presence booleans) and a privacy guarantee that no identifier is ever returned (SEC-PM-006). It also spells out the auth/troubleshooting behavior that annotations cannot express. Rate limits and failure modes remain undisclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight paragraphs: the purpose and return contract come first, then the access constraint. The "SEC-PM-006" internal reference is mildly opaque jargon but costs little and signals a hard rule.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be enumerated, yet the description still previews the important ones. Combined with the explicit auth prerequisite and the read-only annotation, an agent has what it needs to call this correctly; only cross-tool routing guidance is thin.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single id parameter is validated by a 24-hex-char pattern, so the schema does the heavy lifting. The description only says "by ID," adding no format or sourcing hints (e.g., where an ID comes from) beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Get a Circle by ID" names a specific verb and resource, and the follow-up sentence describes what the payload contains (members plus per-member channel presence booleans). It is clearly distinct from list_circles/create_circle/update_circle, though it never names a sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives a concrete precondition (a Proof account, PROOF_API_KEY set, restart then retry) and explicitly rules out a tempting wrong path: start_login does NOT unlock this tool. What is missing is guidance on when to prefer this over list_circles or get_circle_member when the caller does not yet have an ID.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_confirmationARead-onlyInspect
Get a confirmation by ID. Returns the full confirmation including status, response, and proof token.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Confirmation ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| status | Yes | Status of a confirmation request. A confirmation that times out is `denied`, with `response.channel` `system` and `response.text` `timeout`. |
| hitl_id | Yes | |
| message | Yes | The stored ciphertext envelope, echoed back verbatim. The server never sees the plaintext, so this is never the human sentence — the approver decrypts it in their browser. |
| resends | No | Every "Send again" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it. |
| response | No | The decision and its evidence (null while pending) |
| created_at | Yes | |
| timeout_at | No | When this confirmation will time out |
| updated_at | Yes | |
| proof_token | No | Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`) |
| resolved_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and the description adds real context beyond that: the auth setup requirement and restart step, plus the fact that a proof token is part of the payload. It does not note that the proof token is sensitive output or that the confirmation may be pending, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the purpose and return contents front-loaded, followed by a short access block. The access note is somewhat abruptly worded with a run-on 'set ... and restart ... then call' chain but every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with an output schema, an annotation covering safety, and an explicit auth prerequisite, nothing needed to invoke it correctly is missing. The output schema means return values need no further elaboration.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single 'id' parameter, so the schema already documents it. The description adds no guidance on where the ID comes from (create_confirmation, list_confirmations) or its format, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb plus resource ('Get a confirmation by ID') and an explicit statement of what is returned (status, response, proof token). It is clearly distinguishable from create_confirmation, list_confirmations, and wait_for_confirmation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a useful negative routing hint ('start_login does NOT open this tool') and the prerequisite for use (a Proof account with PROOF_API_KEY). However, it never addresses the obvious alternative — wait_for_confirmation — so an agent cannot tell whether to poll this tool or block on the sibling, which is the main selection decision here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_confirmation_approval_linkAInspect
Get the approval link of the HITL config owner: it is decided with the config's own key, so it is for the owner to approve or deny the confirmation themselves. An approver cannot use it — an approver's link goes only to their own channel, and "Send again" (POST /api/v1/confirmations/{id}/resend, which no tool calls yet) is what sends it there again. Every call returns the same owner link until "Send again" reaches the owner; "Send again" replaces it, and the next call returns a new one. Calling this tool again cancels nothing, so it is safe to call again to show the link again. The link expires when the confirmation does. Only works for pending confirmations.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Confirmation ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| approval_url | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavior beyond the annotations: repeat calls are non-cancelling and safe, the same link is returned until 'Send again' replaces it, and the link expires when the confirmation does. However, it never explains why readOnlyHint=false despite describing the tool as cancel-nothing and safe to re-call, leaving a gap between the structured safety profile and the prose. It also front-loads an auth/setup requirement (PROOF_API_KEY, restart, start_login does not unlock it), which is valuable but is operational rather than behavioral detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The key point is front-loaded, but the middle is convoluted: the 'Send again' endpoint is described twice with a parenthetical about no tool calling it, and 'Calling this tool again cancels nothing, so it is safe to call again to show the link again' repeats itself. Several clauses could be compressed without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema, the description covers the operationally important facts: pending-only scope, link lifetime, idempotent re-calls, and the credential prerequisite. What is missing is the link between the confirmation id and the HITL config owner, but the essentials an agent needs to call it correctly are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one parameter with 100% schema description coverage ('Confirmation ID'), so the schema already carries the semantics and baseline 3 applies. The description does nothing to disambiguate whether the id refers to a confirmation or a HITL config, which is exactly the confusion its own first sentence invites.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: it returns the approval link belonging to the HITL config owner, and it explicitly scopes it as owner-only (an approver cannot use it). That distinguishes it from the resend behavior and from the approver path. It is slightly muddled by switching between 'HITL config owner' and 'confirmation' without stating the relationship, so it stops short of a clean 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear usage condition (only works for pending confirmations) and an exclusion (approvers cannot use it — their link goes to their own channel, via the resend endpoint no tool currently calls). It does not compare against near siblings such as get_confirmation or wait_for_confirmation, so the when-to-use framing is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_current_userARead-onlyInspect
Get the signed-in user's account details, plan and settings. Needs a login session: call start_login, then wait_for_login until it reports success. An API key alone cannot read this — for the key's own account use get_self_api_key or get_settings.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| emails | No | |
| created_at | No | |
| phone_numbers | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description adds the crucial behavioral fact that authentication must come from a session rather than a key, plus two access paths (PROOF_API_KEY env var with restart, or sign-in). This is exactly the kind of constraint an agent cannot infer from the schema or annotations and would otherwise fail on repeatedly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the sibling routing are front-loaded in the first sentence, which is ideal. The second paragraph restates the login requirement already given ('call start_login, then wait_for_login'), so the ACCESS block overlaps rather than strictly adding, costing a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A zero-param read tool with an existing output schema needs only purpose and access conditions to be callable, and both are fully covered, including the environment-variable path. Nothing an agent needs at invocation time is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4; nothing needs explaining and the description correctly does not invent parameter guidance. No additional value is possible on this dimension.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get the signed-in user's account details, plan and settings') and explicitly distinguishes itself from the two nearest siblings, get_self_api_key and get_settings, which cover the API key's own account. An agent can pick the right tool without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite chain (start_login, then wait_for_login until it reports success), states a negative condition (an API key alone cannot read this), and names the alternatives to use in that case. When-to-use, when-not, and fallbacks are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_default_templatesARead-onlyInspect
Get the default message templates — one for each channel and message type a message is actually sent for. These are the built-in templates a sub-account sends when it has no custom template of its own.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| defaults | Yes | The platform default of every channel and message type some send renders, keyed message type → channel. A pair nothing sends is left out. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and an output schema exists so return shape is documented. The description's real contribution is the access/auth requirement and the surprising fact that start_login does not grant access — useful context, but it's the only behavioral detail added, and nothing is said about scoping to the calling sub-account or ordering guarantees.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, front-loaded with what the tool returns before the access caveat. The access paragraph is slightly redundant in restating 'call this tool again' but every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with an output schema and readOnlyHint, the description covers purpose, fallback semantics, and the auth gate. The only meaningful omission is routing guidance versus list_templates when the agent actually wants a sub-account's custom templates.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to disambiguate and the baseline of 4 applies. The description correctly implies the call is unscoped by input; any filtering happens server-side.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (default message templates) and adds a precise qualifier: one per channel and message type actually sent, and only the built-ins used when a sub-account has no custom template. That distinguishes it in substance from list_templates/get_template, though it never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear selection context — these are the fallback defaults, not the account's own templates — and states the prerequisite (a Proof account) plus a concrete remedy (set PROOF_API_KEY, restart, retry) and an explicit dead end (start_login does NOT unlock this tool). It stops short of pointing to list_templates as the alternative for custom templates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_delegationARead-onlyInspect
Get one of your delegations by Mongo id or ph_dlg_* handle. Returns the stored publishable token plus the DERIVED effective_status/is_valid — the delegation is only as live as the control proof it stands on (a revoked, suspended or expired domain proof invalidates it) and never outlives its own expires_at, whichever comes first.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Delegation ID (24-hex Mongo id or ph_dlg_<32 hex> handle) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| scope | No | Deprecated. Delegation schema 2.0 carries no scope; this array stays for the SDKs released before it: the scope a delegation issued before schema 2.0 was stored with, otherwise empty. Removed in the next major version. |
| token | No | The signed delegation JWT — the PUBLISHABLE artifact (publish it in your MCP server card under `_meta` → `holdings.proof/delegation`). Same key, algorithm and JWKS as proof tokens |
| status | No | The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on |
| delegate | No | Typed delegate identifier |
| is_valid | No | True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above |
| issued_at | No | |
| principal | No | The proven domain that authorized the delegate — derived from the control proof, never client input |
| created_at | No | |
| expires_at | No | Never later than the control proof's own expiry at issuance (effective expiry is min of the two) |
| revoked_at | No | |
| environment | No | |
| control_proof | No | The control proof handle this delegation points down to |
| delegation_id | No | Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint |
| revoked_reason | No | |
| effective_status | No | DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint: it discloses that the returned token is the stored publishable one, that effective_status/is_valid are DERIVED, that a revoked/suspended/expired domain proof invalidates the delegation, and that it never outlives its own expires_at. That is exactly the kind of invalidation semantics an agent cannot guess from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the capability, followed by the non-obvious derived-status semantics, then a clearly separated ACCESS block. Dense but every sentence carries information; only the identifier-format restatement is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return shape needs no prose, and the description still adds the crucial derivation rules plus the auth prerequisite that would otherwise cause a failed call. For a single-param read tool this covers what an agent needs to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the id property already documents both the 24-hex and ph_dlg_<32 hex> forms with a matching regex, so the description only restates it. The baseline of 3 is appropriate — no additional meaning (e.g. lookup-failure behavior) is conveyed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Get one of your delegations") and even the accepted identifier forms (Mongo id or ph_dlg_* handle). It does not explicitly differentiate itself from the very close sibling get_delegation_token, leaving the agent to infer that this one returns derived status alongside the token.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Prerequisite guidance is strong and explicit (Proof account, PROOF_API_KEY, restart, and the notable exclusion that start_login does NOT unlock this tool). What's missing is when to pick this over list_delegations, get_delegation_token, or verify_delegation — usage context is implied by the object-lookup framing but never routed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_delegation_tokenARead-onlyInspect
Get the current token of an active delegation by its public ph_dlg_* handle — after a signing-key rotation, the re-signed token to publish in place of the old one. Public endpoint — no API key required, since the token is already published with the delegation. Any handle that is not an active delegation (revoked, suspended, expired or unknown) answers the same not_found.
| Name | Required | Description | Default |
|---|---|---|---|
| handle | Yes | Public delegation handle (ph_dlg_<32 hex>) |
Output Schema
| Name | Required | Description |
|---|---|---|
| token | Yes | The delegation token as stored now — the one to publish in place of an older copy |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries most of the behavioral load and does it well: it discloses the public/no-API-key auth model and explains that revoked, suspended, expired and unknown handles all collapse into the same not_found response. That is real added context beyond the annotation, though it says nothing about rate limits or token lifetime/expiry semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose comes first, then the rotation use case, then the auth model and error behavior — a logical front-loaded order with no filler. The em-dash clause makes the opening sentence a little dense, but every sentence contributes information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and a single fully-described parameter, the remaining burdens are auth requirements, error behavior and purpose, all of which are covered. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the handle parameter is already documented with its ph_dlg_<32 hex> pattern, so the baseline is 3. The description reinforces the public-handle semantics and adds that any non-active handle yields not_found, which is useful behavior tied to the parameter but not a new format or syntax detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource ('Get the current token of an active delegation') and scopes it to the public ph_dlg_* handle, which separates it from the metadata-oriented get_delegation and the verify_delegation siblings. An agent can tell what it returns (a token, not delegation metadata) without inspecting the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the concrete triggering situation — after a signing-key rotation, to obtain the re-signed token to publish in place of the old one — which is genuine when-to-use guidance. It does not explicitly name get_delegation as the alternative for non-token reads, so it falls short of full sibling routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dns_providersARead-onlyInspect
Get metadata for all supported DNS providers, including required credential fields and documentation links.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | How many providers are supported. A supported provider with no metadata on record is counted here but not listed in `providers`. |
| providers | Yes | Each supported provider with metadata on record, keyed by provider id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description earns credit for disclosing the authentication requirement (Proof account, PROOF_API_KEY environment variable with a server restart, or a start_login session) and the fact that the tool must be re-invoked after signing in. With an output schema present, it is fair that return values are not enumerated; only the absence of any note about result volume or refresh behavior keeps this below 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single purpose sentence followed by a clearly labeled ACCESS block; every sentence carries information the agent needs, and the access constraint is separated visually rather than buried mid-paragraph.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-argument read tool with an output schema and readOnlyHint, the description covers purpose and the one real complication, authentication. It stops short of telling the agent what the natural next tool is (connect_dns_provider / create_dns_credential) in this very large sibling set.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to document and the baseline of 4 applies. The description correctly implies the call is unfiltered metadata retrieval.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Get metadata for all supported DNS providers') and even enumerates the payload fields returned (credential fields, documentation links). It never distinguishes itself from neighboring tools such as connect_dns_provider, connect_cloudflare, or create_dns_credential, so an agent must infer that this is the discovery step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Access prerequisites are spelled out, and the description explicitly routes an unauthenticated caller to start_login, which is genuine when-to-use guidance. However, it says nothing about when to call this versus the credential-creating or provider-connecting siblings, so the sequencing guidance is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_domainARead-onlyInspect
Get details of a specific domain by ID, including verification status, DNS records, and provider connections.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | Domain record |
| instructions | Yes | How to show control of the domain by the method it is set to |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes the safety profile, and the description adds genuinely useful context beyond it: the required Proof account, the PROOF_API_KEY environment setup, and the start_login session path before retrying. It also previews the kind of data returned, which helps an agent anticipate the shape of the response.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in one sentence, and the access block is separated out so it does not obscure the main function. The access note is somewhat verbose (mentioning both the env-var route and the start_login route), but every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't explain return values, yet it still summarizes them. Auth prerequisites — the most likely failure mode for a fresh agent — are fully covered. The only gap is the absence of guidance on how this relates to sibling domain tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter with 100% schema description coverage, so the schema already carries the semantics. The description's phrase "by ID" confirms the parameter is a domain identifier rather than a name or hostname, but adds no format or lookup detail beyond that. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ("Get details of a specific domain by ID") and enumerates the returned facets (verification status, DNS records, provider connections), which distinguishes it from list_domains, delete_domain, and verify_domain. It stops short of explicitly naming the sibling tools it is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by "by ID" — you need a known domain ID — but there is no explicit statement of when to reach for this versus list_domains or the various verify/check domain tools. The access paragraph covers prerequisites for calling it, not selection guidance among alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_hitlARead-onlyInspect
Get a HITL config by ID. Returns the config including channels, timeout, and status.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | HITL config ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | No | |
| status | Yes | Status of a HITL configuration |
| keypair | Yes | Encryption keypair metadata (null if not configured) |
| user_id | Yes | Owner user ID (useful for SDK encryption AAD) |
| channels | Yes | |
| circle_id | No | Backing Circle for a circle-backed Approvals config (null for channel-list configs) |
| created_at | Yes | |
| profile_id | No | |
| updated_at | Yes | |
| environment | Yes | |
| timeout_seconds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true is consistent with a "Get" operation. Beyond annotations, the description contributes the meaningful non-obvious fact that authentication cannot be established via start_login, which prevents a likely agent failure loop. The return-field summary is largely redundant given a dedicated output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight blocks: purpose and return fields first, then the access caveat. Every sentence is functional, though the "start_login does NOT open this tool" line is phrased defensively and could be folded into a single prerequisite sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool with a full output schema, the description covers what an agent needs: what it fetches, what comes back, and the auth prerequisite. Only the source of a valid HITL config ID (presumably list_hitls) is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single required `id` parameter, so the schema already carries the meaning. The description only echoes the by-ID semantics without adding format hints or where to obtain the ID. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Get a HITL config by ID" gives a specific verb and resource, and the second sentence previews the returned fields (channels, timeout, status). It does not distinguish itself from close siblings such as list_hitls, get_hitl_keys, or get_circle, so an agent must infer that this is the by-ID lookup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS clause gives clear operational context: a Proof account with PROOF_API_KEY configured is required, and start_login will not unlock it. It stops short of explicit routing guidance, e.g., use list_hitls first to discover an ID, or when to prefer update_hitl instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_hitl_keysARead-onlyInspect
Get the encryption keypair for a HITL config. With hitl:read it returns the public key, encrypted private key, KDF salt, and key ID (kid). A key holding confirmations:create without hitl:read receives only public_key and kid — what a confirmation message is sealed to, never the private-key material.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| hitl_id | Yes | HITL config ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| kid | Yes | The key id: lowercase hex SHA-256 of the public key's SPKI DER |
| dek_iv | No | |
| dek_tag | No | |
| kdf_salt | No | The salt the wrapping key is derived with. Absent for a key holding `confirmations:create` without `hitl:read`. |
| public_key | Yes | The RSA public key (SPKI PEM) messages are sealed to. Null means the stored key material could not be read: a degraded state to report, not "no key yet" (a config with no keypair answers 404 `no_keypair`). |
| wrapped_dek | No | The per-config data key wrapped under the master key; null for a keypair stored before it existed. Absent for a requester key, as are the five fields below. |
| backup_dek_iv | No | |
| backup_dek_tag | No | |
| backup_wrapped_dek | No | The same data key wrapped under the recovery key; null until recovery is set up |
| encrypted_private_key | No | The private key as stored, wrapped client-side. Absent for a key holding `confirmations:create` without `hitl:read`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description goes well beyond that by disclosing permission-dependent return shapes, that private-key material is withheld without `hitl:read`, and a hard setup dependency with a restart. This is exactly the auth and scope context an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the resource and the primary return shape, then uses a single compact paragraph for the permission-scoped alternative and access requirements. No filler or repetition; the negated start_login warning earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description usefully flags that the returned keys vary by scope, which the schema cannot express. Combined with the access prerequisite, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is documented as "HITL config ID". The description adds only "for a HITL config", so it does not meaningfully extend parameter meaning beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource ("Get the encryption keypair for a HITL config") and immediately clarifies the two possible payload shapes. It is clearly distinct from siblings like delete_hitl_keys, upload_hitl_keys, and get_hitl.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives strong context on who gets which response based on the caller's scopes, plus an explicit prerequisite path (set PROOF_API_KEY, restart, retry) and a negative exclusion (start_login does NOT open this tool). It does not name the sibling tools to use for key rotation or upload, but the when-to-use conditions are clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_identity_challengeARead-onlyInspect
Get a Proof-Me identity challenge by ID. Returns its status (pending, confirmed, denied, cancelled, failed, expired, revoked or suspended), the channel the CONFIRM ran on, and — once the person being checked decided — the proof token and its proof_id. Poll this for resolution.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Identity challenge ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| status | Yes | The one status every read reports. `pending` — waiting for the person being checked; `confirmed` — they confirmed; `denied` — they denied; `cancelled` — whoever started the check withdrew it; `failed` — the check could not be delivered; `expired` — nobody answered in time; `revoked` / `suspended` — the confirmation's proof was revoked or suspended (`POST /proofs/{proof_id}/revoke` or `/suspend`; revoking a denial's proof leaves it `denied`), or — `revoked` only — the member being checked was removed from the Circle while the check was still pending, which leaves `proof_id` null. Removing a member is not guaranteed to revoke a confirmation they already gave; revoke that one by its `proof_id`. A proof that merely reached its own expiry still reads `confirmed`; whether its token is still valid is `POST /proofs/validate`'s answer. |
| channel | No | Channel the CONFIRM was dispatched on (GET) |
| is_drill | No | True for a drill (scheduled, or started from the dashboard) rather than a real check (GET) |
| proof_id | No | Public handle of the decision's proof — what `POST /proofs/{proof_id}/revoke` takes. Null until a decision minted one (GET). |
| circle_id | No | The Circle the check belongs to (GET) |
| created_at | No | ISO 8601 timestamp |
| expires_at | No | ISO 8601 timestamp |
| proof_token | No | Signed proof token, present once the person being checked decided |
| resolved_at | No | ISO 8601 timestamp of the decision — the CONFIRM, the DENY, the cancellation or the delivery failure — or null while the check is unanswered and after a timeout. |
| confirm_channel | No | Channel the CONFIRM was dispatched on (POST) |
| single_channel_warning | No | True when the account holder has only one channel, so the CONFIRM ran on the same channel as the suspicious contact (degraded) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true is consistent with a 'get' tool, and the description adds real context beyond annotations: the full status enumeration, the fact that the proof token only materializes once the subject has decided, and a prominent authentication precondition with remediation steps. Its one gap is that it doesn't say whether the token/status is stable across subsequent polls or how long an expired/revoked challenge remains retrievable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and return payload, then polls, then access constraints in a separate labeled block. Slightly verbose in the long status list and the shouting ACCESS block, but no sentence is wasted for an agent that will otherwise fail on auth.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A one-parameter read with an output schema and readOnlyHint — the description covers the decision-relevant extras (status semantics, token timing, auth requirement). Return-shape detail is correctly delegated to the output schema, leaving only poll-interval/expiry guidance unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter exists and the schema already documents it at 100% coverage with a 24-hex-character pattern, so the schema carries the semantics. The description's 'by ID' phrasing adds nothing beyond that, which is the baseline case for full-coverage schemas.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a Proof-Me identity challenge by ID') and immediately clarifies the scope of the returned object (status, channel, proof token/proof_id). This clearly separates it from the create_identity_challenge sibling, which would produce such an ID.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Poll this for resolution' gives explicit operational guidance for how the tool is meant to be used, and the ACCESS paragraph explicitly excludes start_login as a path to this tool. It stops short of naming create_identity_challenge as the source of the ID, so the create→poll workflow is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_multi_channel_verification_statusARead-onlyInspect
Get the status of a multi-channel verification group by its group_id. Returns the aggregate status (pending/verified/expired), the winning_channel once one completes, per-channel statuses, and the proof token (with expires_at) when the group is verified.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | Yes | Multi-channel verification group ID (format vg_<hex>) |
Output Schema
| Name | Required | Description |
|---|---|---|
| proof | No | |
| status | No | Group-level status: verified as soon as any channel completes |
| channels | No | Per-channel statuses without per-channel error detail |
| group_id | No | |
| winning_channel | No | Channel that completed the verification (null while pending) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description adds real behavioral context beyond that: the auth/credential gate, an explicit negative disclosure that start_login does not unlock the tool, and a UX constraint about surfacing the link/SMS outside the tool result. Nothing here contradicts the read-only annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and return shape, then the pre-call UX caveat and the access note; each sentence adds information. The access paragraph is slightly tangential to invocation and could be trimmed, keeping it just below top marks.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be enumerated, yet the description does so anyway and still covers the auth gate and a display obligation an agent would otherwise miss. Coverage is strong for a one-parameter read tool; only explicit sibling routing is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single group_id already documents the vg_<hex> format, so the schema carries the parameter semantics. The description only restates 'by its group_id' without adding format, validation, or lookup-failure meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb and resource ('Get the status of a multi-channel verification group by its group_id') plus the exact returned fields (aggregate status, winning_channel, per-channel statuses, proof token). It is clearly not a create/list/mutate tool, though it never names the sibling it is distinguished from, such as wait_for_verification or get_proof_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete precondition ('Before calling this for a challenge you created, make sure your reply text already shows the user what to act on') and an access prerequisite (PROOF_API_KEY, restart, start_login does NOT open this tool). It stops short of stating when to poll this versus blocking on wait_for_verification, so tool-selection routing is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_my_profileARead-onlyInspect
Get the current user's primary profile. Returns profile details, theme, custom links, and public proof display settings.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bio | No | |
| theme | Yes | Profile theme customization |
| username | No | Absent until a username is claimed |
| is_public | Yes | |
| avatar_url | No | A URL or a data URI; null once cleared |
| created_at | Yes | |
| is_primary | Yes | |
| profile_id | Yes | The public id used in profile URLs |
| updated_at | Yes | |
| view_count | Yes | |
| email_theme | Yes | Theme of this sub-account's emails; null when unset (read as `dark`). |
| is_business | Yes | |
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| custom_links | Yes | |
| display_name | No | |
| business_name | No | |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
| support_email | Yes | Support address shown in this sub-account's messages; null when unset. |
| show_delegations | Yes | |
| verification_level | Yes | Always 'basic'; no levels are computed; removed in the next major. |
| show_proof_channels | Yes | |
| show_verification_dates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and the description adds real context beyond that: authentication setup requirements, a restart step, and the fact that the login flow does not unlock this tool. It stops short of noting rate limits or failure modes when the key is absent, which would have pushed it higher.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the capability in one sentence, then separates the access prerequisite into its own labeled block, which is easy to scan. The access paragraph is slightly verbose (restart-and-retry instructions) but each sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists and there are no parameters, so the description does not need to document return shapes; it still summarizes the returned fields helpfully. The one real gap is sibling disambiguation in a toolset dense with profile/user-adjacent endpoints, which is the missing piece for full completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline for a no-arg tool applies. The description correctly implies a no-argument call scoped implicitly to the authenticated user.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Get the current user's primary profile") and enumerates what comes back (profile details, theme, custom links, public proof display settings). It does not, however, distinguish itself from closely named siblings such as get_profile or get_current_user, so an agent must infer the "my" vs "arbitrary profile" distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear precondition (a Proof account plus PROOF_API_KEY set with a server restart) and explicitly rules out a tempting alternative path by stating start_login does NOT open this tool. What it omits is guidance on when to prefer it over get_profile, get_current_user, or update_my_profile.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_platform_summaryARead-onlyInspect
Get a one-call account snapshot: quota with end-of-month projection, request health (pending/completed/expired counts + success rate), per-channel completion rates, HITL counts, and active API key count. The same data the dashboard home renders. The hitl_channels sub-object requires the hitl:read scope.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | No | Scope the metrics and key counts to one sub-account (24 hex characters); the quota stays account-wide | |
| environment | No | Scope request/channel/HITL metrics to test or production data (default: production) |
Output Schema
| Name | Required | Description |
|---|---|---|
| as_of | No | When the snapshot was computed (ISO 8601) |
| quota | No | |
| next_action | No | Most-pressing account action; null when healthy |
| top_channels | No | |
| hitl_channels | No | Present only with hitl:read scope (JWT always) |
| request_health | No | |
| active_api_keys | No | |
| cache_age_seconds | No | Always 0 — computed live |
| channels_with_zero_completions | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only safety, and the description adds real operational context: a Proof account is required, PROOF_API_KEY must be set with a server restart, and the hitl_channels sub-object needs the hitl:read scope. Not disclosed are rate limits or how partial-scope results degrade.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the value proposition, then a separated ACCESS block. Slightly redundant phrasing ('Set PROOF_API_KEY and restart this server, then call this tool again') costs a little, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be explained, yet the description still summarizes what the snapshot contains. Account prerequisite and scope requirement are both covered; only failure/refresh behavior is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are documented in-schema, including the 24-hex pattern, the enum, defaults, and the fact that quota stays account-wide. The description adds no parameter detail beyond the schema; only the hitl:read scope note touches output, not inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a one-call account snapshot') and then enumerates the exact contents: quota with projection, request health counts, per-channel completion rates, HITL counts, API key count. That enumeration separates it cleanly from siblings like get_usage, get_webhook_stats, and get_current_user.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'same data the dashboard home renders' framing plus the access note ('start_login does NOT open this tool') gives clear context on when it applies and steers the agent away from a plausible wrong path. It never names an alternative for narrower questions (e.g. point to get_usage), so it stops short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profileARead-onlyInspect
Get a specific profile by ID. Returns full profile details including theme, custom links, and verification display settings.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | Yes | Profile ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bio | No | |
| theme | Yes | Profile theme customization |
| username | No | Absent until a username is claimed |
| is_public | Yes | |
| avatar_url | No | A URL or a data URI; null once cleared |
| created_at | Yes | |
| is_primary | Yes | |
| profile_id | Yes | The public id used in profile URLs |
| updated_at | Yes | |
| view_count | Yes | |
| email_theme | Yes | Theme of this sub-account's emails; null when unset (read as `dark`). |
| is_business | Yes | |
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| custom_links | Yes | |
| display_name | No | |
| business_name | No | |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
| support_email | Yes | Support address shown in this sub-account's messages; null when unset. |
| show_delegations | Yes | |
| verification_level | Yes | Always 'basic'; no levels are computed; removed in the next major. |
| show_proof_channels | Yes | |
| show_verification_dates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already covers the safety profile, and the description adds important behavioral context: this tool requires a Proof account and PROOF_API_KEY configuration. It also clarifies that start_login does not open this tool, which is useful authentication-flow context beyond the annotations. It does not cover error behavior or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loads the tool's purpose before the access note. The return-content sentence is somewhat redundant because an output schema exists, but overall the wording is efficient and easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only lookup with an output schema and one fully described parameter, the description provides enough context to call the tool correctly. The main remaining gap is lack of explicit routing guidance against sibling profile-read tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage for the single profile_id parameter, so the schema already documents the parameter. The description only says 'by ID' and adds no format, examples, or constraints beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb and resource: get a specific profile by ID. It also names return content including theme, custom links, and verification display settings. It does not explicitly differentiate from siblings such as get_my_profile or list_profiles, but the by-ID scope is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when a profile ID is known and gives an important access prerequisite. However, it does not explicitly say when to use this tool instead of get_my_profile or list_profiles, nor does it provide exclusion guidance beyond noting that start_login does not open this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profile_assetsARead-onlyInspect
Get available verified assets that can be displayed on the user's profile. Returns assets eligible for public proof display.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | No | The sub-account whose shown proofs set each asset's is_public flag (24 hex characters); omitted, the primary |
Output Schema
| Name | Required | Description |
|---|---|---|
| assets | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes this is a safe read, and the output schema covers return values. The description does add meaningful auth context (Proof account required, PROOF_API_KEY env var plus server restart, start_login insufficient) that cannot be derived from structured fields. It says nothing about scoping behavior when profile_id is omitted beyond what the schema already states, so it is solid but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose comes first, then the access requirement, in three short sentences with no filler. The 'restart this server, then call this tool again' instruction is operational but earns its place by preventing a failed call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-optional-parameter read tool with annotations and an output schema, the description covers purpose and the blocking prerequisite, which is the main failure mode. The only real gap is sibling differentiation from list_assets and update_profile_proofs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single profile_id parameter is already documented with its 24-hex pattern and default-to-primary behavior. The description adds no additional meaning about the parameter, which is acceptable given the schema does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get available verified assets that can be displayed on the user's profile') and clarifies the returned subset ('eligible for public proof display'). It does not, however, distinguish itself from close siblings such as list_assets, get_asset, or update_profile_proofs, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear eligibility condition for use (assets that can be shown publicly on a profile) plus an explicit exclusion: start_login does NOT unlock this tool. It stops short of naming which alternative to call when the prerequisite is unmet, leaving the agent to figure out the API-key path itself.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_proof_statusARead-onlyInspect
Get the status of a proof by its public handle (ph_ctl_* / ph_dlg_*) or a verification ID. Returns whether the proof is active, suspended, expired, or revoked — a live proof reads "active".
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Public proof handle (ph_ctl_* / ph_dlg_*) or verification ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | No | Current status of the proof — `active` is a live proof, `suspended` the reversible pause |
| is_valid | No | |
| proof_id | No | Public proof handle (`ph_ctl_<32 hex>`), or a verification id for a legacy proof |
| expires_at | No | |
| is_expired | No | |
| is_revoked | No | |
| revoked_at | No | |
| suspended_at | No | When the current suspension began (null unless status is `suspended`) |
| revoked_reason | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint, so the description does real work: it discloses the authentication prerequisite and explicitly warns that start_login does not grant access, which is a non-obvious failure mode. It also lists the state vocabulary the caller should expect back. It does not cover error behavior for malformed or unknown IDs, keeping it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded sentences: capability plus returned states first, then access prerequisites. The access paragraph is slightly verbose but carries non-obvious information, so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the annotations plus the access note cover the safety and prerequisite picture for a one-parameter read tool. The only gap is behavior on invalid or unknown identifiers, which an agent might reasonably want to know.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter is fully documented in the schema, so the description mostly restates the accepted handle formats and verification-ID option. That restatement adds mild emphasis but no syntax, format, or resolution-order details beyond what the schema already provides, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (get the status of a proof) and enumerates the possible states (active, suspended, expired, revoked), plus the accepted identifier forms (ph_ctl_*/ph_dlg_* handles or verification IDs). It does not explicitly distinguish itself from near siblings like validate_proof, get_verification, or get_proof_token, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied by the identifier formats and the note that start_login does not unlock this tool, but there is no explicit guidance on when to pick this over validate_proof, get_verification, or get_proof_token. The stated precondition (PROOF_API_KEY must be set) is genuinely useful, though it is a setup note rather than a when-to-use rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_proof_tokenARead-onlyInspect
Get the current token of a proof you own, by its public ph_ctl_* handle. After a signing-key rotation this is the re-signed token, which replaces any older copy you hold. Each read is audited. A revoked or expired proof answers proof_not_live; a suspended one is still served. The proof of one of the account's own verified assets (a domain, phone or email verified on the account itself) answers owner_session_required here whatever its status (with a live key; a test key gets not_found): this tool sends the API key, and such a token is read by the signed-in owner in the dashboard. A key bound to a sub-account reads only that sub-account's proofs; another's answers not_found. For a delegation (ph_dlg_*) use get_delegation_token or get_delegation instead.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Public proof handle (ph_ctl_<32 hex>) |
Output Schema
| Name | Required | Description |
|---|---|---|
| token | Yes | The proof token as stored now. After a key rotation it is the re-signed token under a newer `kid`: every claim is kept except `iat`, which is the re-signing time, and a token issued before schema 1.2 also gains the `jti` and `proof_id` its registry row records. |
| status | Yes | Live statuses only — a revoked or expired proof answers 410 `proof_not_live` instead |
| proof_id | Yes | Public proof handle (`ph_ctl_<32 hex>`) |
| expires_at | Yes | |
| reissued_at | Yes | When the token was last re-signed under a newer key; null if it never was |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses non-obvious behavior: the token is re-signed after a signing-key rotation and supersedes any older copy, every read is audited, revoked/expired returns proof_not_live while a suspended proof is still served, and the account's own verified assets return owner_session_required (not_found with a test key). These are exactly the surprises that would otherwise derail an agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Scope and identifier form come first, then edge-case behavior, then the separate ACCESS note, so the structure is front-loaded and navigable. It is dense and a few clauses (the test-key parenthetical) could be trimmed, but nearly every sentence carries operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is a single-parameter read with an output schema, so return-value shape needn't be re-explained; the description instead uses its space for access prerequisites and error semantics. Nothing an agent needs to call this correctly — auth, key scoping, error cases, alternatives — is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the id parameter is already documented as ph_ctl_<32 hex>; the description largely restates the handle form. It does add real meaning about how the handle resolves: a sub-account-bound key reads only that sub-account's proofs, and another's handle answers not_found.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource ('Get the current token of a proof you own') plus the required identifier form (ph_ctl_* handle). It explicitly routes delegation handles (ph_dlg_*) to get_delegation_token/get_delegation, so an agent can separate it from the nearest sibling without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the alternative tools for delegation proofs and the condition that selects them, and calls out account access prerequisites (PROOF_API_KEY required; start_login does not unlock this tool). It also explains what to expect for revoked/expired versus suspended proofs, which is usage-relevant guidance rather than marketing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_request_by_referenceARead-onlyInspect
Get a verification request by its reference ID (your unique identifier).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| reference_id | Yes | Your unique reference ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| assets | No | |
| status | No | Status of a verification request |
| progress | No | |
| created_at | No | |
| expires_at | No | |
| partial_ok | No | |
| updated_at | No | |
| action_type | No | Type of action for verification request or authorization |
| callback_url | No | The webhook URL set on the request, if any |
| completed_at | No | |
| redirect_url | No | |
| reference_id | No | |
| action_context | No | The action the person is asked to authorize; null when the request carries none |
| computed_state | No | Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces. |
| verification_url | No | URL for the verification flow |
| validity_requirement | No | Required proof freshness as set on the request (e.g. "7d"); null when none was set |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, so the description earns credit for the extra context it supplies: the account/auth prerequisite, the required restart step, and the non-obvious fact that start_login will not unlock this tool. It does not say what happens on an unknown reference_id (empty result vs error), which is the remaining behavioral gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence is front-loaded and the access caveat is separated out, so an agent can stop reading once it has credentials. No redundant restatement of the parameter or title; the wording is slightly awkward ('does NOT open this tool') but each sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read with an output schema and readOnlyHint present, the description covers purpose, the identifier source, and the auth prerequisite. The only meaningful omission is disambiguation from the cluster of verification-request siblings and not-found behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and reference_id is described, so the schema carries the load. The description adds only the clarification that the reference is 'your unique identifier' (i.e., caller-supplied rather than server-generated), which is mildly useful but does not add format, case-sensitivity, or lookup-failure semantics. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Get') and resource ('a verification request') plus the lookup key ('reference ID'), which is concrete enough to act on. It implicitly distinguishes itself from the many list/get siblings by naming 'reference ID (your unique identifier)', but never names get_verification_request or get_verification, so the agent must infer which of the several get-request tools this is.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a real invocation prerequisite (needs a Proof account, PROOF_API_KEY set, server restarted) and an explicit exclusion ('start_login does NOT open this tool'). However, there is no guidance on when to use this versus get_verification_request, list_verification_requests, or get_request_proofs — the sibling set is dense with plausibly overlapping choices.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_request_proofsARead-onlyInspect
Get proof tokens for verified assets in a verification request. Returns proof tokens that can be used for offline verification.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification request ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| proofs | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a read-only operation. The description adds meaningful behavioral context by explaining that the returned proof tokens can be used for offline verification and by spelling out the account/API-key prerequisite, which is not visible from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded with purpose and then access constraints, with no unnecessary wording. Both paragraphs are short and each sentence serves a clear operational purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema, read-only annotation, and fully documented parameter, the description covers the essentials an agent needs. It could still be improved by placing this tool more explicitly relative to proof-token siblings, but the access requirement is a useful addition.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The sole parameter has full schema coverage and is documented as the verification request ID. The description implies the same meaning but adds no syntax, format, or validation details beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: it gets proof tokens for verified assets within a verification request. That scope clearly distinguishes it from related tools like get_proof_token or validate_proof, though it does not explicitly name those alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The access prerequisite is clearly stated, including the PROOF_API_KEY requirement and the warning that start_login will not unlock this tool. However, it gives no explicit guidance on when to use this versus sibling tools such as get_proof_status or get_proof_token.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_self_api_keyARead-onlyInspect
Get the calling API key's own redacted metadata (id, name, key_prefix, environment, scopes, last_used_at, revoked_at, created_at) for agent self-inspection. Never returns the key hash or full secret. Requires API-key auth — a JWT session has no single-key context (returns 400 api_key_required).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | Yes | |
| scopes | Yes | |
| created_at | Yes | |
| expires_at | No | When the key stops authenticating; null means it never expires. Enforced at authentication — an expired key is rejected exactly like an unknown one. |
| key_prefix | Yes | |
| profile_id | No | Sub-account (PublicProfile) the key is bound to; null for unbound keys. |
| revoked_at | No | When the key was revoked; null while it is live |
| environment | Yes | |
| last_used_at | No | When the key last authenticated a request; null if never |
| replaced_key_ids | No | Ids of the keys this key replaced, newest first: the earlier keys of the same integration, replaced when the key was regenerated (`POST /api/v1/me/api-keys/{id}/regenerate`) or renewed by an MCP sign-in refresh. Requests and usage of those keys count as this key's. Empty when it replaced none. Recorded from the release of key history on; a key replaced before it is not linked. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, but the description adds the crucial disclosure that the key hash and full secret are never returned, plus the exact failure mode (400 api_key_required) for JWT callers. It also front-loads the auth requirement and environment-variable setup, so the agent knows both the safety profile and the preconditions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sections: a front-loaded purpose sentence with the field list and secret-exclusion guarantee, then a clearly labeled ACCESS block for the auth prerequisite. The ACCESS paragraph is slightly wordy in restating the retry step, but every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless read tool with an output schema, the description covers what an agent needs: what it returns, what it deliberately omits, what auth context it requires, and how to recover when the required auth is missing. Nothing material is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero input parameters, so baseline is 4 and there is no parameter meaning to add. The listed response fields are arguably redundant with the existing output schema, but they add no harm and give a quick preview of what the call returns.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: retrieve the *calling* API key's own redacted metadata, and enumerates the returned fields (id, name, key_prefix, environment, scopes, timestamps). The word 'own' implicitly separates it from the sibling list_api_keys, but no sibling is named explicitly, so differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the use case ('agent self-inspection') and the exclusion condition clearly: a JWT session has no single-key context and will get a 400 api_key_required. It also explains the setup prerequisite (set PROOF_API_KEY and restart) and explicitly rules out start_login as an alternative path, which is unusually strong negative guidance. It stops short of pointing the agent to list_api_keys for multi-key inspection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_sessionARead-onlyInspect
Get a session by ID. Returns the session status, verification details, and proof token if verified.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | Session id |
| proof | No | Proof token after successful verification |
| status | No | |
| channel | No | How the person proves the number: `telegram` or `whatsapp` (the bot reads the number from their account), or `sms` (they text a short code from the number to one of ours). |
| created_at | No | |
| verified_at | No | Once `verified` |
| phone_number | No | The proven number (once `verified`) |
| verification_id | No | The verification record created on completion (once `verified`) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered, and the description adds real operational context: a Proof account is required, PROOF_API_KEY must be set with a server restart before retrying. That is exactly the kind of auth/prerequisite disclosure that annotations cannot express. Minor gap: nothing about behavior when the session ID is unknown or the session is unverified beyond the conditional "if verified".
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs, front-loaded with the purpose and return contents, with the access prerequisite isolated so it is easy to scan. Nothing is redundant, though the ACCESS block reads as setup instructions rather than tool semantics.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A one-parameter read tool with an output schema and readOnlyHint has little it must explain, and the description covers purpose, return shape, and the auth prerequisite that would otherwise cause a silent failure. Only the sibling-selection question (get_session vs wait_for_session) is left unanswered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single required `id` string, so the schema already carries the parameter meaning. The description only echoes it as "by ID" and adds no format, prefix, or lookup guidance. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Get a session by ID" is a specific verb+resource, and the second sentence enumerates what comes back (status, verification details, proof token). It does not explicitly distinguish itself from sibling readers like wait_for_session or list_auth_sessions, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a concrete negative routing hint — "start_login does NOT open this tool" — which preempts a likely agent mistake, plus the prerequisite for making the call work at all. It never names the alternative tool to use when the session is not yet ready (e.g. wait_for_session), so it is clear context rather than full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_settingsARead-onlyInspect
Get account settings: the outbound webhook endpoint with its event subscriptions, and the default proof lifetime. Branding (name, logo, colour, email theme, support email) belongs to each sub-account: read it with get_profile. The webhook signing secret is NOT returned to an API key — the response reports webhook.secret_set instead, and the value itself is visible only in the dashboard or in the update_settings response that created or rotated it.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| hitl | No | Approval-setup settings. |
| webhook | No | Outbound webhook configuration — DEPRECATED (#421). An account switched over to webhook endpoints sees its account-wide (`legacy`) endpoint here: `url` is null while that endpoint is disabled, a `url` write updates or creates it, `url: null` disables it (its secret is kept), and `rotate_secret` rotates its secret. An account not yet switched over sees its settings fields, as before. Omitted for an API key bound to one sub-account. |
| proof_expiry_days | No | Default lifetime in days of newly issued verification proofs, or null when the account has never set one. Confirmation-decision proofs do not use it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description goes well beyond by disclosing that the webhook signing secret is never returned to an API key, that webhook.secret_set is reported instead, and where the raw value can actually be seen. The ACCESS paragraph adds authentication requirements and the restart step, which no annotation covers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the resource contents, then the sibling routing, then the secret caveat, then access. Every sentence carries information, though the ACCESS block is somewhat verbose relative to a single prerequisite and could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the description only calls out the one return-field exception an agent could misread (secret vs. secret_set). Combined with the access prerequisite, nothing needed to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to add and the baseline applies; the description instead spends its words on return-value caveats. That is a reasonable trade, though it is not adding anything the schema needs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource (account settings) and enumerates the exact contents: outbound webhook endpoint with event subscriptions, and default proof lifetime. It also draws the boundary against sub-account branding, so an agent can distinguish it from get_profile without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent elsewhere for branding ("read it with get_profile") and states the precondition for calling this tool at all. It even pre-empts a likely wrong turn by declaring that start_login does NOT open this tool, which is the kind of exclusion that prevents wasted calls.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_subscriptionARead-onlyInspect
Get the current subscription details including plan, status, billing period, and usage limits.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| plan | Yes | Plan to check out. `free` adds a card for pay as you go (the metered price past the included proofs); it is offered once billing is live. |
| status | Yes | Stripe's status for the subscription, whatever it is (the caller decides what counts as subscribed); null when the account has no subscription. |
| scheduled_plan | No | The plan a scheduled downgrade moves the account to at `scheduled_change_at`; null when nothing is scheduled. Absent from an API that predates plan changes. |
| current_period_end | Yes | End of the current billing period; null without a subscription. |
| scheduled_change_at | No | When the scheduled downgrade takes effect (the end of the paid period); null when nothing is scheduled. |
| cancel_at_period_end | Yes | Whether the subscription ends at the end of the current period; false without a subscription. |
| current_period_start | Yes | Start of the current billing period; null without a subscription. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety needs no restating. The description instead adds real behavioral context the annotations do not carry: the tool requires an authenticated Proof account via PROOF_API_KEY, needs a server restart to pick it up, and is explicitly NOT unlocked by start_login — a non-obvious failure mode worth flagging.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence comes first and is followed by a clearly separated ACCESS block, so the structure is easy to scan. The access block is slightly verbose ('then call this tool again'), but each clause carries actionable information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless read tool with an output schema, the description covers purpose and the authentication prerequisite, which is the main thing that can go wrong. The only real gap is lacking differentiation from sibling usage/balance tools, a minor omission for something this simple.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is nothing for the description to disambiguate at the input level. Mentioning plan, status, billing period, and usage limits describes the response shape rather than parameters, which is mild redundancy given an output schema exists.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Get the current subscription') and enumerates the returned fields: plan, status, billing period, usage limits. It does not distinguish this from closely related siblings such as get_usage, get_balance, or get_platform_summary, so an agent must infer the boundary itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear prerequisite for calling the tool (a Proof account plus PROOF_API_KEY set and a server restart) and explicitly rules out start_login as a way to unlock it. What it never states is when to reach for this tool instead of get_usage or get_balance, which cover overlapping billing/usage territory.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_templateARead-onlyInspect
Get the template a sub-account sends for a channel and message type: its custom template if set (scope "project"), otherwise the default (scope "default"). The response names the sub-account in profile_id.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Message channel | |
| profile_id | No | The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key | |
| message_type | Yes | Message type (e.g. verification_request, login_request) |
Output Schema
| Name | Required | Description |
|---|---|---|
| scope | No | `project` — the sub-account's own template; `default` — the platform default it falls back to. |
| template | No | Message template |
| is_custom | No | |
| profile_id | No | The sub-account resolved for this request; null for an account with no sub-account yet. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description stays consistent with that while adding real context: the scope-resolution fallback logic, the fact that the response carries the sub-account in profile_id, and a concrete auth prerequisite (set PROOF_API_KEY, restart the server, and note that start_login does not unlock this tool). The auth/restart caveat is exactly the kind of operational detail annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence is front-loaded with the resolution semantics and does the heavy lifting. The second paragraph is operational boilerplate but short and genuinely actionable; nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return shape needn't be described, and the description covers resolution behavior and auth prerequisites. It is silent on the no-template / invalid message_type edge case, but that is a minor omission for a three-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and profile_id already documents the omitted-value default, so the schema carries the parameter burden. The description adds only modest meaning beyond it — that channel and message_type jointly select the template, and that profile_id also appears in the response to identify the sub-account.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get the template ... for a channel and message type') and adds the resolution rule: custom template (scope "project") wins, otherwise the default (scope "default"). That distinguishes it from a plain listing tool, though it never names the close siblings list_templates or get_default_templates explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The fallback sentence implies when to use it (you want the effective template actually sent, not the raw catalogue), and the access paragraph tells the agent it needs a Proof account. But there is no explicit 'use X instead when you want Y' routing against get_default_templates, list_templates, or preview_template/render_template.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_usageARead-onlyInspect
Get usage metrics for the authenticated account. Shows verification counts, API calls, and quota usage.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| months | No | Number of months of history | |
| period | No | Month to query in YYYY-MM format (e.g. 2026-01) |
Output Schema
| Name | Required | Description |
|---|---|---|
| plan | Yes | |
| limit | Yes | The plan's included verifications per month |
| balance | Yes | The prepaid balance as `GET /me/billing/balance` reports it, without `billing_enabled` (the usage read carries that itself) |
| periods | Yes | The months asked for that have a record, newest first |
| hard_limit | Yes | |
| percentage | Yes | `current_usage` as a percentage of `limit`, rounded |
| is_on_track | Yes | null when fewer than 5 days have passed or usage is 0 |
| card_on_file | Yes | |
| top_channels | Yes | |
| current_usage | Yes | Verifications, confirmations, authorizations and delegations this month, counted from the requested months' records: 0 when `period` names another month, since the current month's record is then not among them |
| current_period | Yes | The current month, `YYYY-MM` |
| days_remaining | Yes | |
| billing_enabled | Yes | |
| projected_eom_usage | Yes | |
| projection_unreliable | Yes | true when the projection exceeds the limit three times over |
| channels_with_zero_completions | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and the description adds genuinely non-obvious operational context: the tool requires a Proof account, requires PROOF_API_KEY to be configured and the server restarted, and explicitly does not become available through start_login. That auth/setup disclosure is exactly the kind of behavior annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the function, followed by a short access block separated by a blank line. Two tight paragraphs with no filler; the only mild noise is the operational verbosity around setting an env var and restarting.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be described, and the input schema fully documents both optional parameters. The description covers purpose, reported metrics, and the blocking access requirement, leaving nothing an agent would need before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters (months with 1-12 bounds, period with a YYYY-MM pattern and example) are documented in the schema. The description adds nothing about months vs period, whether they are mutually exclusive, or which wins if both are supplied, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ("Get usage metrics for the authenticated account") and enumerates contents: verification counts, API calls, quota usage. That distinguishes it reasonably well from account-level siblings like get_balance or get_subscription, though it never names a sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an access precondition (needs a Proof account, set PROOF_API_KEY, start_login will not unlock it) but no guidance on when to prefer this over get_api_key_usage, get_platform_summary, or get_balance, which plausibly overlap on usage/quota data. Usage is implied by the reported content rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_user_domain_verification_statusARead-onlyInspect
Get the current status of a domain verification session, including challenge details.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Domain verification session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| domain | Yes | |
| status | Yes | |
| channel | Yes | |
| challenge | No | What is still to be published, while the session is not verified (no `instruction`, unlike the start) |
| created_at | Yes | |
| session_id | Yes | |
| verified_at | No | Present once `status` is `verified` |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already covers the safe-read profile, and the description consistently matches it. It adds context beyond the annotations: an account or key prerequisite and the important detail that 'a session opens this tool,' meaning the data is scoped to an authenticated session. It does not mention rate limits, caching, or whether status can be polled repeatedly, but the auth behavior is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first sentence, followed by a clearly separated ACCESS block. Both parts are short, and the second part is operational rather than filler. The only inefficiency is that the access instructions could be terser, but they are directly relevant to successfully invoking the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a single required parameter, a readOnly annotation, and an output schema that documents the returned challenge details, the description covers what an agent needs to call the tool successfully. The remaining gap is disambiguation from similarly named verification-status siblings. In a server with roughly 130 tools, that keeps it short of a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage for the single parameter, so the baseline is 3. The description adds no meaning about the session_id beyond what the schema already says, such as whether it comes from start_user_domain_verification or how an invalid ID behaves. The schema does the heavy lifting here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: 'Get the current status of a domain verification session, including challenge details.' That is clearer than a bare restatement of the name, and it adds the useful detail that challenge data is returned. However, among the many near-identical siblings in this server (check_domain_verification, check_user_domain_verification, start_user_domain_verification), nothing in the description tells the agent which one this tool is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block provides real usage guidance: the tool requires a Proof account, an API key, or a login session, and the description says to restart the server or use start_login, then retry. However, it gives no guidance on when to choose this tool over the domain-verification siblings, or whether it is the polling counterpart to start_user_domain_verification. Usage guidance is implied by the sibling naming rather than stated explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_verificationARead-onlyInspect
Get a verification by ID. Returns the full verification object including status, channel, and proof token if verified.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| type | No | Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account. |
| proof | No | Proof token after successful verification |
| status | No | Current status of the verification |
| channel | No | Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken. |
| attempts | No | |
| challenge | No | Challenge details for verification |
| created_at | No | |
| identifier | No | The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it |
| updated_at | No | |
| verified_at | No | |
| max_attempts | No | |
| external_user_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover only readOnlyHint=true, and the description goes meaningfully beyond that: it discloses the access prerequisite (a Proof account, PROOF_API_KEY set, server restart) and explicitly warns that start_login will NOT unlock this tool, which prevents a common failed-auth loop. It stops short of saying anything about error or not-found behavior, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short paragraphs, front-loaded with the purpose and return contents before the operational caveats. Every sentence carries information; the only slight inefficiency is that the return-value sentence partly duplicates what the output schema already provides.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the description needn't enumerate return fields, and the auth prerequisite plus the start_login warning cover the main non-obvious failure mode. The remaining gap is disambiguation within a very large set of similarly named verification tools, which is the highest-risk confusion for an agent here.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single required 'id' already documented as 'Verification ID', so the schema carries the parameter burden. The description adds no format, prefix, or source information for the ID (e.g. where to obtain it), leaving it at the baseline for fully documented schemas.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a verification by ID') and adds what comes back ('full verification object including status, channel, and proof token if verified'). It does not, however, distinguish this from the crowded set of verification siblings such as get_verification_request, get_multi_channel_verification_status, or get_proof_status, so an agent still has to infer which verification family this covers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied through the 'challenge you created' framing and the pre-call reminder to surface the link/SMS text to the user, which is genuinely useful sequencing guidance. But there is no explicit when-to-use versus when-to-use-an-alternative statement (e.g. poll once vs. use wait_for_verification), so the routing decision is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_verification_requestARead-onlyInspect
Get a verification request by ID. Returns the request with all its asset verification statuses.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification request ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| assets | Yes | |
| status | Yes | Status of a verification request |
| progress | No | |
| created_at | Yes | |
| expires_at | Yes | |
| partial_ok | Yes | |
| updated_at | No | |
| action_type | Yes | Type of action for verification request or authorization |
| callback_url | No | The webhook URL set on the request, if any |
| completed_at | No | |
| redirect_url | No | |
| reference_id | No | |
| action_context | No | The action the person is asked to authorize; null when the request carries none |
| computed_state | No | Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces. |
| verification_url | No | URL for the verification flow |
| validity_requirement | No | Required proof freshness as set on the request (e.g. "7d"); null when none was set |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already state readOnlyHint=true, and the description is consistent with that. Beyond annotations it discloses the access prerequisite (a Proof account, PROOF_API_KEY set, server restart) and that login-based flows do not unlock this tool — meaningful operational context. It does not describe behavior for invalid or inaccessible IDs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight blocks: what it does and returns first, then the access prerequisite. No filler, and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be restated, and the description still summarises it in one clause. The authentication barrier — the main practical obstacle to a successful call — is covered. The only gap is lack of guidance for lookup by reference or listing, which sits with siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single required `id` parameter, and the description adds no format, prefix, or sourcing detail beyond "Verification request ID." Baseline 3 is appropriate when the schema fully documents the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ("Get a verification request by ID") and adds what is returned ("the request with all its asset verification statuses"). It does not explicitly distinguish itself from near-neighbours like get_verification or get_request_by_reference, so differentiation is left implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is clear: call it with a request ID. It also explicitly rules out an alternative path by warning that "start_login does NOT open this tool," which is concrete when-not guidance. It does not cover siblings such as get_request_by_reference or list_verification_requests for lookup by other keys.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_verified_userARead-onlyInspect
Get a single verified user and their verifications by external user ID.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| external_user_id | Yes | The external user ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| verifications | No | |
| types_verified | No | |
| external_user_id | No | |
| verification_count | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is set by structured data; the description adds real value by disclosing the authentication/environment requirement and the restart-and-retry loop. It does not describe what happens when the user is unknown or unverified, which is the main behavioral gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the action and scope, then a clearly labeled ACCESS block. The restart instruction is slightly operational boilerplate but earns its place by preventing a failed call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return shape need not be explained, and the auth prerequisite is covered. What is missing is failure behavior for nonexistent or unverified users, which matters for a lookup tool keyed on an external identifier.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one parameter with 100% schema description coverage, so the schema already documents it. The description only restates that the lookup key is an external user ID, adding no format or sourcing detail beyond that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — retrieving one verified user plus their verifications, keyed by external user ID. The word 'single' implicitly separates it from list_verified_users, though no sibling is named explicitly, which keeps it just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete precondition (a Proof account with PROOF_API_KEY set) and an explicit exclusion — start_login will not unlock this tool — which steers the agent away from a plausible wrong path. It stops short of saying when to prefer this over list_verified_users or get_user_domain_verification_status.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_webhook_deliveryARead-onlyInspect
Get details of a single webhook delivery attempt including request/response payloads and retry history.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook delivery ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| url | Yes | |
| status | Yes | Delivery status |
| payload | Yes | The event body as stored. Every `proof_token` in it is null: the body POSTed to the receiver carries the token, read from its record at send time, and delivery history keeps no copy. |
| attempts | Yes | |
| created_at | Yes | |
| event_type | Yes | Type of webhook event. `proof.suspended`/`proof.unsuspended` fire for a delegation (`ph_dlg_*`) lifecycle act on the account's own configured webhook_url — not a channel to a separately-addressed delegate (h-fix-delegation-suspend-governance). `proof.reissued`/`delegation.reissued` say a stored token was re-signed under a new key: a reference only (`proof_id` or `handle`, `kid`, `reissued_at`, `token_url`, and the `profile_id` every body carries), never the token; `proof.*` does not cover `delegation.reissued`. |
| profile_id | Yes | The sub-account whose event it was. Null for an account-level event, and for deliveries recorded before #421. |
| updated_at | Yes | |
| endpoint_id | Yes | The webhook endpoint it was sent to. Null for a request's `callback_url` and for a delivery to the account's settings webhook URL before the switch-over to endpoints. |
| delivered_at | Yes | |
| max_attempts | Yes | |
| error_message | Yes | |
| next_retry_at | Yes | |
| response_body | Yes | The receiver's response body. |
| last_attempt_at | Yes | |
| response_status | Yes | |
| token_omitted_reason | No | Why the last send carried `proof_token: null`. Every attempt, the first included, sends the token the delivery was queued with, or null: a retried delivery carries the same `proof_token` as the first attempt or `proof_token: null`, never a different token. `source_gone`: the record holding the token no longer exists, or (for a delivery stored before tokens were left out of history) could not be identified. `token_absent`: it holds no token, or there was none when the delivery was queued. `token_changed`: its token is no longer the one the delivery was queued with (re-issued or changed since). Null when every token was sent. Absent from an API that predates it. |
| verification_request_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds context beyond that: it discloses the payload content of the response (request/response bodies plus retry history) and an environmental auth requirement that the annotations cannot express. It does not cover rate limits or behavior for a nonexistent/malformed ID, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in one tight sentence, and the access caveat is separated into its own block so it does not obscure the main function. Slightly more space is spent on authentication housekeeping than on the tool's actual semantics.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read tool with an output schema present, the description covers purpose, response content, and the auth blocker an agent will hit. Nothing essential is missing, since return-value structure is handled by the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter with 100% schema description coverage ('Webhook delivery ID'), so the schema fully documents it. The description adds no format, prefix, or sourcing details about the ID, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb and resource ('Get details of a single webhook delivery attempt') and enumerates what is returned (request/response payloads, retry history). The word 'single' implicitly separates it from list_webhook_deliveries and retry_webhook_delivery, but no sibling is explicitly named as an alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACESS block gives a real prerequisite (PROOF_API_KEY must be set, restart required) and explicitly rules out start_login as an authentication path, which is useful routing. However, there is no guidance on when to reach for this instead of list_webhook_deliveries or retry_webhook_delivery; the usage context is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_webhook_endpointARead-onlyInspect
Get one webhook endpoint by ID. The signing secret is not returned (only create_webhook_endpoint and rotate_webhook_endpoint_secret return it).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook endpoint ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| url | No | HTTPS URL deliveries are POSTed to, at most 2000 characters. Private, loopback and link-local addresses are refused. |
| scope | No | `all` — every sub-account, present and future, plus account-level events. `selected` — only the sub-accounts in `profile_ids`; account-level events never reach it. |
| events | No | |
| legacy | No | The endpoint converted from the account's single webhook URL — the one the deprecated `/me/settings` webhook block reads and writes. |
| status | No | A `disabled` endpoint receives nothing; its history and secret are kept. |
| created_at | No | |
| secret_set | No | Whether the endpoint has a signing secret (always true). |
| updated_at | No | |
| description | No | |
| profile_ids | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=true, so the description carries most of the burden and adds substantive context: the signing secret is deliberately omitted from the response, and access is gated on an environment variable plus a server restart. The explicit warning that start_login will NOT open this tool prevents a plausible wrong turn. Missing: whether secret omission applies to updates or what other sensitive fields are redacted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then the secret-omission caveat, then the access block — a sensible order. The access sentences are slightly wordy ('restart this server, then call this tool again') but each clause carries unique information. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple read-only getter with a full output schema, so return values need no explanation, and the description still covers the one surprising gap (absent secret) plus access requirements. Nothing an agent needs in order to call it correctly appears to be missing. It could be a 5 with a pointer to how to obtain a valid ID.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single documented id parameter including a 24-hex-char pattern, so the schema does the work. The description only repeats 'by ID' and adds no format, source, or lookup hints beyond it. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (get one webhook endpoint) and scopes it to a single item by ID, which distinguishes it from the list sibling. It also names create_webhook_endpoint and rotate_webhook_endpoint_secret as the tools that do return the signing secret, giving useful contrast. It stops short of a fully explicit routing sentence (e.g. use list_webhook_endpoints to obtain IDs), so a 4 rather than a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete precondition: a Proof account with PROOF_API_KEY set and the server restarted, and explicitly rules out start_login as a way to unlock this tool. That is real when/when-not guidance. It does not discuss pagination-adjacent alternatives or when to prefer re-fetching vs. using data from another call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_webhook_statsARead-onlyInspect
Get webhook delivery statistics including total deliveries, success/failure counts, and recent activity.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| by_status | Yes | |
| delivery_rate | Yes | Delivered share of all deliveries, a percentage with one decimal and a `%` sign; `0%` when there are none |
| recent_failures_24h | Yes | Failed deliveries last updated in the past 24 hours |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the rest and does add real operational context: a Proof account is required, PROOF_API_KEY must be set, the server must be restarted, and start_login will not unlock this tool. What it omits is any indication of the aggregation window ('recent activity' is undefined), rate limits, or whether stats are per-endpoint or global.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence is front-loaded and dense with concrete return fields, and the access requirement is separated into its own labeled block. The all-caps phrasing and 'restart this server, then call this tool again' wording are slightly verbose but carry actionable setup detail rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't spell out return values, and for a zero-parameter read tool the auth prerequisite is the main thing an agent could get wrong. The remaining gap is scope: it never says whether statistics cover all webhook endpoints or one, or over what time range.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter meaning for the description to add; the baseline for a parameterless tool applies. The scope question (all endpoints vs. one) is instead a coverage gap, not a parameter-documentation gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get webhook delivery statistics') and enumerates the metrics returned (totals, success/failure counts, recent activity). It does not explicitly name how it differs from close siblings like list_webhook_deliveries or list_webhook_endpoints, but the aggregate-vs-listing distinction is inferable from the wording.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can guess this is the aggregate/rollup view versus the per-delivery listing tools, but the description never says 'use this for summary metrics, use list_webhook_deliveries for individual records.' The ACCESS block is a prerequisite gate rather than when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
invite_circle_memberAInspect
Mint a single-use enrollment invite for a Circle member. Returns Telegram + WhatsApp deep links and a QR code; the member taps the channel-matched link to bind their messenger identity to the Circle.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| member_id | Yes | Member ID to invite |
Output Schema
| Name | Required | Description |
|---|---|---|
| token | No | |
| qr_code | No | QR code data URL for the primary deep link |
| qr_text | No | UTF-8 text representation of the QR code |
| member_id | No | MongoDB ObjectId |
| expires_in | No | |
| telegram_deep_link | No | |
| whatsapp_deep_link | No | |
| suggested_share_text | No | Suggested message to forward with the invite |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false and destructiveHint=false; the description adds substantive context beyond that: the invite is single-use (a created, non-idempotent artifact), it returns Telegram and WhatsApp deep links plus a QR code, and binding happens on the member's side. It also discloses the auth prerequisite and the fact that start_login will not satisfy it, which is exactly the kind of operational detail annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight paragraphs: capability and return shape first, then the access blocker. Every sentence carries information, and the prerequisite is separated and front-labeled 'ACCESS'. Minor cost is the slightly awkward 'call this tool again' clause, but nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation with an output schema, this covers what an agent still needs: what is produced, that it is single-use, and the account/key prerequisite that would otherwise cause a failed call. Return values are already documented by the output schema, so the description need not go deeper there.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both required parameters (Circle ID, Member ID), so the schema already carries the semantics. The description reinforces that the invite targets a specific Circle membership but adds no format, constraint, or interaction detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Mint a single-use enrollment invite for a Circle member', then explains the mechanism (member taps a channel-matched deep link to bind messenger identity). It is clearly distinct from generic verification tools in the sibling list, but it never names the adjacent siblings (add_circle_member, add_circle_member_channel, create_circle_member_drill) that an agent could easily confuse with this one, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete precondition and a clear routing exclusion: a Proof account is needed, PROOF_API_KEY must be set with a server restart, and 'start_login does NOT open this tool'. That prevents a plausible wrong path. It does not explain when to prefer this over add_circle_member or add_circle_member_channel, which is the remaining usage gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_api_keysARead-onlyInspect
List all API keys for the authenticated account. Returns key metadata (not the secret key values).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered, and the description adds genuinely useful context: auth prerequisites and the fact that secret key values are never returned. That caveat prevents an agent from expecting secrets in the response. Beyond that it discloses nothing about ordering, pagination, or what happens with revoked keys — though the output schema likely covers the return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks with the purpose leading and the access prerequisite following; the critical 'not the secret key values' caveat is placed early. The ACCESS paragraph is operational rather than descriptive, but it carries real information an agent needs to succeed on first call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Everything an agent needs is present: what is listed, what is excluded from the response, the auth precondition with a recovery path, and an output schema that defines the return shape. The only missing piece is differentiation against the singular/usage sibling tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a no-param tool is 4. The description correctly implies no filtering or scoping arguments are accepted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'List all API keys for the authenticated account' — and clarifies the return scope ('key metadata (not the secret key values)'). It is distinguishable from siblings like create_api_key or revoke_api_key by the list verb, though it never explicitly contrasts with get_self_api_key or get_api_key_usage, which are the closest neighbours.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete prerequisite guidance: a Proof account is required, and it names two paths to satisfy that (set PROOF_API_KEY and restart, or sign in with start_login then re-call). It does not say when to prefer this over get_self_api_key or get_api_key_usage, so it stops short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_assetsARead-onlyInspect
List all verified assets for the authenticated user. Assets are verified identities (phones, emails, domains).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Filter by asset type | |
| status | No | Filter by status |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read, so the description's added value is the authentication/configuration requirement and the explicit failure mode with start_login — non-obvious behavioral facts the annotations cannot express. Pagination and default filtering behavior (e.g. what happens with no type/status filter) are still undisclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: purpose first, resource definition second, then a clearly labeled ACCESS block. The remediation steps ('Set PROOF_API_KEY and restart this server, then call this tool again') are operational but earn their place because the tool is otherwise unusable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Return shape is covered by the output schema and parameters are fully documented, so the description only needed to add access prerequisites and resource semantics — both of which it does. It falls short of complete because an agent still cannot predict the no-filter default or result volume.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with both parameters enumerated, so the schema carries the parameter burden. The description's gloss on what an 'asset' is gives partial meaning to the type filter, but it does not clarify whether filters are ANDed, what status means for domains vs wallets, or whether omitted filters return everything.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List all verified assets for the authenticated user') and defines the resource ('Assets are verified identities (phones, emails, domains)'), which implicitly distinguishes it from the narrower list_phones / list_emails / list_domains siblings. It never names those siblings explicitly, so the routing is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a concrete precondition (a Proof account with PROOF_API_KEY set, server restarted) and an explicit negative: 'start_login does NOT open this tool', which saves an agent from a plausible but wrong path. It does not say when to prefer this over the type-specific sibling list tools, which is the remaining gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_authorizationsARead-onlyInspect
List authorizations with optional filters. Returns paginated results.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| phone | No | Filter by phone number | |
| status | No | Filter by authorization status | |
| channel | No | Filter by channel |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes that this is a safe read operation. The description adds useful behavioral context by stating pagination and the Proof account / PROOF_API_KEY requirement, including a specific authentication caveat about start_login.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded with the core purpose before the access caveat. Every sentence carries useful information, though the access note is somewhat procedural.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is a straightforward filtered list with full schema coverage, an output schema, and read-only annotations. The description covers purpose, pagination, and authentication prerequisites; only sibling-selection guidance is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already documents page, limit, and each filter. The description mentions optional filters and pagination but adds no syntax or semantic detail beyond the schema, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: list authorizations, with optional filters and paginated results. It distinguishes the resource clearly enough, though it does not explicitly contrast with sibling tools like list_auth_sessions or export_authorizations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear access prerequisite and explicitly notes that start_login does not unlock this tool. However, it provides no guidance on when to use this versus get_authorization, export_authorizations, or other listing tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_auth_sessionsARead-onlyInspect
List the current user's signed-in devices: every session that can still renew, idle ones included. Each shows its channel, user agent and expires_at, which is when the session stops being able to renew (not when its current access token expires). When called via API key, no session is marked is_current.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| total | No | |
| sessions | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint, but the description adds genuine behavioral context: idle/inactive sessions are included, the exact fields returned, a clarification that expires_at is the renewal cutoff rather than access-token expiry, and the edge case that no session is marked is_current when called via an API key.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and scope are front-loaded in the first sentence, then the required semantic clarification, then access in its own block. Slightly padded by the setup instructions, but no sentence is redundant or off-topic.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter read tool with an output schema (which covers the return shape), the description supplies everything else an agent needs: scope, an edge-case caveat, the expires_at interpretation, and authentication prerequisites.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero input parameters, so the baseline is 4. The description instead disambiguates the meaning of fields in the result, which is useful but not the dimension's focus.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('List the current user's signed-in devices') and defines scope precisely: 'every session that can still renew, idle ones included.' An agent knows exactly what comes back. It does not name the sibling it is not (revoke_auth_session), so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear precondition (needs a Proof account, set PROOF_API_KEY, restart, retry) and an explicit exclusion ('start_login does NOT open this tool'), which prevents a real mistake. It stops short of routing the agent to revoke_auth_session for revocation, so alternatives are only implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_balance_ledgerARead-onlyInspect
List the prepaid balance history, newest first: every top-up, refund and adjustment, and one usage row per month for that month's deductions. Amounts are signed euro cents (credits positive).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| limit | No | Rows per page (default 20, max 100) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and the description does not contradict them. On top of that it discloses ordering (newest first), the sign convention for amounts (signed euro cents, credits positive), and the granularity of usage rows, which are behaviors the annotations cannot convey; the only gap is that pagination/navigation behavior is left entirely to the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks: the content/semantics sentence first, then the access precondition. Every clause carries information an agent needs, with no repetition of schema or annotation data.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-structure explanation is rightly omitted, and the access requirement plus sign convention cover the non-obvious risks. What remains slightly thin is guidance on iterating pages and interpreting the per-month aggregation, but overall it is complete for a read-only list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both parameters (page, limit) are fully documented with defaults and maxima in the schema itself. The description adds no pagination semantics or format details beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('List the prepaid balance history') and enumerates exactly what the rows are: top-ups, refunds, adjustments, and one monthly usage row for deductions. It never names the closely related sibling get_balance (current balance rather than history), so the distinction must be inferred from the word 'history'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states an explicit precondition and recovery path: set PROOF_API_KEY, restart the server, then call again, plus a clear exclusion that start_login does NOT unlock this tool. That is unusually useful routing guidance, but there is no explicit guidance on when to prefer this over get_balance or how to page through large histories.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_circle_member_channelsARead-onlyInspect
List a Circle member's channels. Returns channel metadata only (channel, status, verified_at) — an identifier is NEVER returned (SEC-PM-006).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| member_id | Yes | Member ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| channels | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint=true annotation is consistent with the read-only listing behavior. Beyond annotations, it discloses the exact return shape (channel, status, verified_at) and a hard security constraint that no identifier is ever returned (SEC-PM-006), plus the account/API-key prerequisite, which is genuinely useful context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences lead with the action, then layer the return contract and access requirement. The access sentence is slightly verbose ('call this tool again') but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be enumerated, yet the description still summarizes them; auth prerequisites and the security constraint round it out. Only the relationship to sibling member/channel tools is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with both parameters ('id' = Circle ID, 'member_id' = Member ID) documented, so the baseline is 3. The description adds no further meaning such as ID formats or whether the member must belong to the circle.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource ('List a Circle member's channels'), which is unambiguous on its own. It never names a sibling (e.g., list_circle_members or remove_circle_member_channel) to contrast with, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains prerequisites for access (needs a Proof account, set PROOF_API_KEY, restart the server) and rules out one path ('start_login does NOT open this tool'). However, it gives no when-to-use guidance versus alternatives such as list_circle_members, so usage is only partly covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_circle_membersARead-onlyInspect
List a Circle's members. Each member carries channel-presence booleans (has_telegram / has_whatsapp) and the masked phone they enrolled from (enrolled_phone_hint, e.g. +9••••••4171) — a full identifier is NEVER returned (SEC-PM-006).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| members | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond readOnlyHint=true by disclosing the returned fields (has_telegram, has_whatsapp, enrolled_phone_hint), the masking rule, and the policy reference SEC-PM-006 that a full identifier is never returned. It also surfaces the authentication prerequisite, which is behavioral context an agent cannot get from annotations. It stops short of describing ordering, pagination, or failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight blocks: what is returned first, then the access gate. Every sentence carries information — the masked-phone example clarifies the format without a diagram, and the SEC-PM-006 reference is compact provenance rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description was not obliged to enumerate return fields, yet it helpfully flags the privacy guarantee that the schema alone would not convey. For a one-parameter, read-only list tool, the only real gap is the absence of any statement about result size or ordering.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single id parameter has 100% schema description coverage ("Circle ID" with a 24-hex pattern), so the schema already carries the semantics. The description adds no format, sourcing, or lookup guidance for obtaining the Circle ID, so it earns only the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List a Circle's members") and immediately characterizes what each member record contains. It does not explicitly distinguish itself from siblings such as get_circle or list_circle_member_channels, so an agent must infer the boundary rather than being told.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use versus alternative guidance relative to get_circle or list_circles. The access block does supply a genuine exclusion — that start_login will not unlock this tool and PROOF_API_KEY plus a restart is required — which is useful routing information, but it addresses authentication, not tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_circlesARead-onlyInspect
List Circles with optional filters. Archived Circles are excluded by default; pass status="archived" to surface them. Returns paginated results.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| limit | No | Items per page (default 20, max 100) | |
| status | No | Filter by status (archived excluded unless requested) | |
| profile_id | No | Filter by bound public profile (sub-account) | |
| environment | No | Filter by environment (production or test) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered; the description adds the non-obvious default-filtering behavior (archived excluded) and notes results are paginated. It also discloses the auth prerequisite that a caller must satisfy before the call will succeed, which is exactly the kind of context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two front-loaded sentences cover behavior and one short access block covers prerequisites; nothing is padded. The access sentence is slightly verbose in its step-by-step instructions, but it earns its place because it prevents a futile call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and 100% parameter documentation, the description only needs to add filtering defaults and access requirements, and it does both. A brief note on result ordering or total-count fields would make it fully complete, but nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so page, limit, status, profile_id, and environment are already documented in the input schema, establishing a baseline of 3. The description restates the status filter's archived behavior but adds no new detail on page/limit bounds, profile_id format, or environment semantics beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: "List Circles with optional filters," which cleanly separates it from get_circle, create_circle, and update_circle among the siblings. It does not explicitly name those siblings, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete usage rule — archived Circles are hidden unless status="archived" is passed — plus an explicit exclusion telling the agent that start_login does NOT unlock this tool and that PROOF_API_KEY must be configured instead. This is strong routing guidance, though it does not enumerate alternate listing/pagination strategies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_confirmationsARead-onlyInspect
List confirmations with optional filters. Returns paginated results with status, HITL config and sub-account (profile_id) filtering.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| status | No | Filter by confirmation status | |
| hitl_id | No | Filter by HITL config ID | |
| end_date | No | Only confirmations created on or before this instant (ISO 8601) | |
| profile_id | No | Only this sub-account's confirmations (sent through its HITL configs or created by its keys) | |
| start_date | No | Only confirmations created on or after this instant (ISO 8601) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered, but the description adds real context the schema cannot: results are paginated and the tool is gated on an API key with a restart step, plus the explicit warning that start_login does not unlock it. Return shape detail is unnecessary because an output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause, and the access block is clearly separated and actionable. The second sentence partly repeats the filter list already implied by the first sentence, which is minor redundancy rather than bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With seven all-optional parameters, full schema coverage, an output schema, and readOnly annotations, the remaining burden on the description is purpose plus access gating, both of which it delivers. Nothing an agent needs to invoke this read-only listing correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so page, limit, status, hitl_id, profile_id, and the date bounds are already fully documented with formats and enums. The description merely restates that status, HITL config, and profile_id are filters, adding no syntax, default, or interplay guidance beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ("List confirmations") and notes that all filters are optional, which distinguishes it from the singular get_confirmation sibling. It does not explicitly name which sibling to use instead when the agent already has an ID, leaving that inference to the reader.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives one genuinely useful usage rule: the tool requires a Proof account configured via PROOF_API_KEY and is explicitly NOT unlocked by start_login, which prevents a plausible wrong path. However, it says nothing about when to prefer this listing over get_confirmation or wait_for_confirmation, or whether pagination should be iterated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_delegationsARead-onlyInspect
List your own delegations with optional filters. Each item carries the DERIVED effective_status/is_valid beside its stored status — read effective_status, since status records only whether the owner revoked the delegation themselves, so a delegation still reads active there after its domain control proof was revoked, suspended or expired, and after its OWN lifetime ran out. effective_status accounts for all of those: it reports expired once either lifetime has passed, whichever is earlier. Tokens are not included in the list — use get_delegation for the stored token. There is no public enumeration of third-party delegations.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| status | No | Filter by the delegation's OWN stored status (active|revoked). Does NOT filter the derived effective_status — status=active still returns delegations whose control proof died, and ones that simply ran out. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| pagination | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries most of the burden and delivers: it explains that effective_status is derived, that stored status only reflects owner-initiated revocation, that the proof can be revoked/suspended/expired, and that expiry uses the earlier of two lifetimes. It also discloses that tokens are omitted and that the tool requires an authenticated Proof account. The only gap is no mention of pagination behavior or result ordering, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is front-loaded with the core action first, then the status caveat, then the token exclusion, then access requirements. Some phrasing is dense and repeats what the status enum description already says, but nearly every sentence conveys a distinct constraint an agent would otherwise get wrong.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-shape detail is unnecessary. The description covers the remaining risk areas for this tool: auth requirements and the exact remediation, the derived-vs-stored status trap, missing token data with a pointer to the right tool, and the absence of third-party enumeration.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real interpretive value by explaining why the status filter is misleading (it ignores control-proof death and lifetime expiry) and how effective_status resolves it. Page and limit are left entirely to the schema, which is acceptable given their self-explanatory descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with explicit scope: 'List your own delegations with optional filters.' It also carves out the boundary against siblings by noting tokens are excluded and that 'There is no public enumeration of third-party delegations,' so an agent can distinguish it from get_delegation and the various list_* siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to an alternative ('use get_delegation for the stored token') and tells it which field to read and why ('read effective_status'). It also documents a prerequisite path in the ACCESS block (PROOF_API_KEY, restart, and that start_login does NOT unlock this tool), which is exactly the when/when-not guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_dns_credentialsARead-onlyInspect
List all stored DNS provider credentials for the authenticated account. Returns credential metadata (not secret values).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and the description is consistent with a pure read. Beyond the annotations, it adds two substantive facts: the returned data is credential metadata and not secret values (important for an agent worried about leaking secrets), and the call requires an authenticated Proof account with PROOF_API_KEY or a session from start_login. It does not cover pagination or result limits, but with an output schema present that is a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs: purpose and return scope first, then access prerequisites. Front-loaded and free of filler. The access paragraph is slightly verbose in restating the restart requirement, but it earns its place by preventing a predictable auth failure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only list tool with an output schema and readOnlyHint, the description covers what the tool does, what it returns (metadata, not secrets), and the authentication prerequisite. The remaining omission is whether the list is paginated or bounded, which the output schema may already answer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter meaning to add and the baseline of 4 applies. The description correctly describes a global, unfiltered listing, which matches the empty input schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'List all stored DNS provider credentials for the authenticated account.' The scope ('all', 'for the authenticated account') is explicit, so it is distinguishable from create_dns_credential and delete_dns_credential. It does not name or contrast with sibling list/read tools like get_dns_providers or check_domain_credentials, which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'List all stored DNS provider credentials' — the agent can infer this is the read/inspect operation — but there is no explicit when-to-use guidance and no statement of when to prefer get_dns_providers, check_domain_credentials, or verify_domain_with_credentials instead. The ACCESS section usefully tells the agent to call start_login first if unauthenticated, which is a real routing hint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_domainsARead-onlyInspect
List all domains for the authenticated account. Returns domain metadata including verification status.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description is consistent with that. Beyond the annotations it discloses the authentication prerequisite and the failure mode, plus what kind of data comes back ('domain metadata including verification status'), which is meaningful operational context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence front-loads purpose, the second states the return content, and the ACCESS block is separated and actionable. Phrasing like 'a session opens this tool' is slightly awkward, but there is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description needn't enumerate return fields, and it correctly summarizes them in one clause. For a zero-parameter read tool the requirements are modest, and the auth prerequisite is the main thing an agent would otherwise trip on — that is covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4; there are no argument semantics the description needs to compensate for. The schema is empty and 100% covered, so nothing is left ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List all domains') and scopes it to the authenticated account, which implicitly separates it from the sibling get_domain for a single domain. It does not explicitly name that sibling, but an agent can tell this is the collection lister.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives a concrete remediation path when unauthenticated (set PROOF_API_KEY and restart, or call start_login) which is real when-to-use guidance. However, there is no guidance on when to prefer this over get_domain, or when listing versus adding/verifying a domain is the right call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_emailsARead-onlyInspect
List all email addresses associated with the authenticated account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| emails | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the read-only nature needs no restating. The description adds real value beyond that by documenting the authentication prerequisite and the concrete recovery path (set PROOF_API_KEY and restart, or sign in via start_login and retry) — a behavior an agent would otherwise only discover by failing. It doesn't state whether unverified or pending addresses are included, which is the main remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the purpose and followed by the access requirement, with no filler. The second sentence is somewhat dense, stacking the env-var path and the sign-in path in one em-dash construction, but every clause is actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values don't need explaining, and the auth prerequisite — the main failure mode for this call — is covered. What's missing is a note on what the listing includes (verified vs. pending addresses, primary designation), which would matter for a tool whose siblings include set_primary_email and remove_email.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a parameterless tool applies. Nothing in the description conflicts with the empty input schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'List all email addresses associated with the authenticated account,' with an explicit scope ('all', 'authenticated account'). An agent can easily distinguish it from siblings such as list_phones, list_domains, and list_profiles because of the 'email addresses' resource, but the description never explicitly names an alternative or boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear context on when this becomes usable: it requires a Proof account, either via PROOF_API_KEY set before restart or a session opened by start_login, after which the tool can be called. It does not explain when to prefer this over related tools like list_profiles or get_current_user, and it gives no exclusions, so it stops short of full 5-level guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_hitlsARead-onlyInspect
List HITL configs with optional filters. Returns paginated results.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| status | No | Filter by status (active or archived) | |
| profile_id | No | Only this sub-account's configs (24 hex characters) | |
| environment | No | Filter by environment (production or test) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| limits | Yes | |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered; the description adds genuinely new behavior: paginated results, a required Proof account with PROOF_API_KEY set and server restart, and the explicit exclusion of start_login as an unlock path. Defaults for page/limit and result ordering are still unstated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one sentence, pagination note second, and the ACCESS block is separated and clearly labeled. Nothing is padded, though the restart-the-server instruction is operational noise for an agent that cannot act on it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the schema fully documents all five optional parameters. The description covers the auth precondition and pagination, leaving only default page size and sort order unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and every parameter carries its own description, enum, or pattern, so baseline is 3. The description's 'optional filters' and 'paginated results' only loosely gesture at status/profile_id/environment and page/limit without adding format or default semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List HITL configs with optional filters') and adds that results are paginated, which tells an agent this is the enumeration counterpart to get_hitl. It never names a sibling explicitly, so the distinction from get_hitl/create_hitl rests on the verb alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the verb (enumerate configs when you have no specific ID) but there is no explicit when-to-use / when-not-to-use language or routing to alternatives. The ACCESS block does give a crucial prerequisite and warns that start_login does not unlock this tool, which is real guidance even if it is about auth rather than tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_incoming_requestsARead-onlyInspect
List incoming verification requests where the authenticated user is the subject.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, but the description adds information the annotations cannot: authentication is required and how to satisfy it, plus the fact that the call must be repeated after a session opens. It says nothing about result volume or ordering, though an output schema exists to carry the return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded sentences: scope first, then access. The access sentence is slightly awkward ('a session opens this tool') but every clause carries operational value and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless read-only list tool with an output schema, the description covers the two things an agent cannot derive from structured fields: the subject-scoped filter and the auth requirement. The remaining gap is explicit disambiguation from the near-identical list_my_requests and list_verification_requests siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so there is no parameter semantics to explain; the empty object schema is self-evident. The baseline for zero parameters applies, with no contradicting or misleading text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('List incoming verification requests') and adds a real scoping qualifier — 'where the authenticated user is the subject' — which separates it from the many other list_* verification tools. It stops short of naming the closest alternatives (list_my_requests, list_verification_requests), so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states a concrete prerequisite (a Proof account via PROOF_API_KEY or start_login) and tells the agent to retry after authenticating, which is genuine when-to-use context. However, it never says when to prefer this over list_my_requests or list_verification_requests, which is the main selection risk given the crowded sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_my_requestsARead-onlyInspect
List verification requests created by the authenticated user.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| api_key_id | No | Only requests created with this API key or a key it replaced (24 hex characters); an API key may name only itself | |
| profile_id | No | Only this sub-account's requests (24 hex characters) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| stats | Yes | Requests per status across every page, under the same filters except `status` |
| pagination | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description goes further by disclosing the authentication requirement and the exact bootstrap sequence (API key env var plus restart, or start_login then re-call). That is behavior an agent cannot get from the annotation or schema. What is missing is result-set behavior such as pagination or ordering, though the presence of an output schema lowers the cost of that omission.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the purpose and then the access requirement; there is no filler. The phrasing "a session opens this tool" is slightly compressed but still parseable, and the whole thing fits the reader's attention budget.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema covering return values and readOnlyHint covering the safety profile, the description only needs purpose and access context, both of which it supplies. The residual gap is sibling disambiguation among the three list-request tools, which matters given this tool's placement in a very large, similarly named tool set.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both optional filters are documented with format constraints and an unusual rule ("an API key may name only itself"). The description adds nothing about parameters, so the schema carries the full burden and baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ("List verification requests") and narrows the scope to those "created by the authenticated user", which is a meaningful distinction from an unfiltered list. It does not, however, name or contrast with the near-identical siblings list_verification_requests and list_incoming_requests, so the agent must infer which of the three list tools is correct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives a concrete prerequisite and a recovery path (set PROOF_API_KEY, or sign in via start_login and retry), which is real when-to-use guidance. But there is no guidance on choosing this tool over list_verification_requests or list_incoming_requests, the sibling set most likely to cause a mis-selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_phonesARead-onlyInspect
List all phone numbers associated with the authenticated account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| phones | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already declares that this is a safe read, so the description doesn't need to restate that. What it does add is the auth gating: the call fails without PROOF_API_KEY or an active session from start_login, and the session can be opened with start_login before retrying. That is genuine operational context, though it reads as server-wide boilerplate rather than tool-specific behavior such as ordering or empty-list handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition opens with the one-line purpose, which is the right front-loading, then puts the access caveat second. Both sentences carry information, although "a session opens this tool" is slightly awkward phrasing for what is really "an existing session authorizes this call."
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a zero-parameter read tool with an output schema, so the description does not need to describe the returned phone records. The auth prerequisite is the main thing an agent could trip on, and it is covered. Only minor gaps remain, such as whether results are ordered or whether an empty account returns an empty list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline applies. The description correctly implies the only implicit input is the authenticated account context, and it does not invent parameters that don't exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ("List all phone numbers") plus a scope ("associated with the authenticated account"), so the agent knows exactly what it returns. It does not explicitly distinguish itself from siblings like list_emails or remove_phone, but the resource noun is unambiguous enough that confusion is unlikely.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence covers a prerequisite (an authenticated Proof account) and two ways to satisfy it, PROOF_API_KEY or start_login. That is login guidance rather than when-to-use guidance: nothing says how this differs from start_add_phone, remove_phone, or set_primary_phone, or when an agent should list rather than mutate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_profilesARead-onlyInspect
List all profiles for the authenticated account. Returns all profiles including primary and secondary.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| profiles | Yes | The primary first, then by creation |
| max_profiles | Yes | How many sub-accounts the plan allows; -1 for no limit |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint already covers the safety profile, so the description's real contribution is the authentication prerequisite and the warning that a login flow will not satisfy it — a genuine behavioral trap it defuses. Pagination or result-size behavior is not mentioned, which is a minor gap given the finding is 'all profiles'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs, each front-loaded: what it returns first, then the access gate. No filler, and the access caveat is set apart rather than buried mid-sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return shape need not be explained, and the key operational blocker (credential setup) is spelled out. The only missing piece is guidance against the near-duplicate profile-reading siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so there is nothing for the description to disambiguate; the schema is effectively empty. Baseline of 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('List all profiles') and adds scope detail ('including primary and secondary') that separates it from the single-profile siblings like get_profile and get_my_profile. It stops short of naming those siblings explicitly, so the differentiation is inferential rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives useful setup context (needs PROOF_API_KEY, restart the server) and rules out a plausible wrong path ('start_login does NOT open this tool'). It does not say when to prefer this over get_profile or get_my_profile, which are the closest siblings in a very large tool list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_reissued_proofsARead-onlyInspect
List your proofs whose token was re-signed at or after an instant, oldest first — what to re-fetch after a signing-key rotation, for example when a webhook was missed. Items are references {proof_id, reissued_at, token_url}, never tokens: pull a ph_ctl_* item with get_proof_token and a ph_dlg_* item with get_delegation_token. Proofs of the account's own verified assets are not listed here (the API key cannot read their tokens); the dashboard shows them. A key bound to a sub-account lists only that sub-account's proofs and the account's delegations.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| since | Yes | ISO-8601 instant with an offset, e.g. 2026-10-01T00:00:00Z |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes | Pagination info in list responses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only assert readOnlyHint=true; the description goes well beyond that by disclosing that items are references rather than tokens, giving the reference shape {proof_id, reissued_at, token_url}, specifying oldest-first ordering, and noting that a sub-account-bound key sees only that sub-account's proofs. The access block also spells out the PROOF_API_KEY requirement and the need to restart the server, which is the kind of operational behavior an agent cannot infer from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action, then proceeds to result shape, sibling handoffs, scope exclusions, and access requirements. It is dense but each sentence carries operational value; the access paragraph is slightly long but necessary for a tool that fails without the right account.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with three params, a full output schema, and existing annotations, the description covers the remaining unknowns: what the returned references mean, how to exchange them for tokens, which proofs are out of scope, and what credentials are required. Nothing an agent needs in order to call and interpret this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents 'page', 'limit', and 'since' with an ISO-8601 example. The description still adds meaning beyond the schema by clarifying the inclusive lower bound ('at or after an instant') and the result ordering ('oldest first'), which affects how a caller interprets 'since' relative to pagination.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause names the exact verb, resource, and filter: 'List your proofs whose token was re-signed at or after an instant, oldest first.' The reader immediately knows this is a filtered read over reissued proofs, not a token-fetch or revocation list, and the ordering guarantee is stated up front.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete triggering scenario — re-fetching after a signing-key rotation or a missed webhook — and routes the agent to the follow-up tools by prefix (get_proof_token for ph_ctl_*, get_delegation_token for ph_dlg_*). It also states an exclusion: proofs for the account's own verified assets are not listed here, plus an access prerequisite and an explicit negative ('start_login does NOT open this tool').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_revoked_proofsARead-onlyInspect
Get the revocation list for offline proof validation. Returns a signed list of all revoked proof IDs. Reuse a fetched list for up to 5 minutes (its cache lifetime), then fetch it again to see new revocations; if you cannot, its signature stays verifiable offline for 1 hour.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| kid | Yes | Key id of the signing key, for JWKS lookup |
| count | Yes | Number of entries in `revoked` |
| revoked | Yes | |
| has_more | Yes | True when a source hit its cap and the list may be incomplete — re-baseline and prefer the Token Status List, which never truncates |
| issued_at | Yes | When this list was generated |
| signature | Yes | Signature over the payload for offline verification, in the algorithm of the key `kid` names (null when unsigned) |
| status_list_uri | Yes | The Token Status List endpoint — the scalable status channel that also covers SUSPENDED and can retract entries (an unsuspended bit flips back; a CRL entry cached by a `?since` poller cannot be unpublished) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation by disclosing two distinct freshness windows: a 5-minute cache lifetime and a 1-hour offline signature verifiability window. That is exactly the staleness information an agent needs to decide whether a cached list is still trustworthy.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose and followed by the caching rule. Every clause carries operational meaning — cache lifetime and signature lifetime are both load-bearing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Return values are covered by the output schema and safety by the readOnlyHint annotation, so the description only needed to supply the freshness semantics, which it does completely. Nothing required to call or trust the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4; there is nothing for the description to disambiguate. It correctly adds no redundant parameter prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get the revocation list') and scopes it precisely to 'offline proof validation', which separates it from sibling reads such as get_proof_status, get_request_proofs, and validate_proof. The second sentence reinforces exactly what is returned: a signed list of all revoked proof IDs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: fetch this when you need revocation data for offline validation, reuse for up to 5 minutes, refetch to pick up new revocations. It does not explicitly exclude alternatives (e.g., when to call validate_proof instead), so it stops short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_templatesARead-onlyInspect
List the custom message templates of one sub-account, organized by channel and message type. Templates belong to a sub-account, not to the account: profile_id picks it — omitted, a sub-account key lists its own sub-account and an account-wide key the primary sub-account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | No | The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key |
Output Schema
| Name | Required | Description |
|---|---|---|
| sendable | No | What a template is sent for. Always sent; absent from an API that predates it. |
| profile_id | No | |
| custom_templates | Yes | |
| available_channels | Yes | |
| available_variables | Yes | |
| available_message_types | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds context the annotation cannot carry: the authentication prerequisite, the required restart, and the notable fact that the login flow does not satisfy it. That is precisely the kind of operational behavior an agent needs before wasting a call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Scope and grouping come first, then the sub-account ownership rule, then a clearly separated ACCESS block. Two sentences carry a lot without padding, though the ACCESS note sits somewhat outside the tool's functional description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one optional parameter fully documented and an output schema present, the description need not explain return values; it covers the non-obvious risks instead (sub-account scoping, auth prerequisite, login-flow dead end). Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so profile_id is already documented, and the description largely restates the same omitted-parameter default logic. It phrases the account-wide-key case slightly more explicitly, but adds little meaning beyond the schema — baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — list the custom message templates — plus the scope (one sub-account) and the grouping (by channel and message type). The word 'custom' implicitly separates it from get_default_templates and the singular get_template, though neither sibling is named outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives real prerequisite guidance (needs a Proof account, PROOF_API_KEY, restart) and explicitly rules out start_login as a way in, which is genuinely useful. However, it never says when to call this versus get_template, get_default_templates, or preview_template, so alternative selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_verification_requestsARead-onlyInspect
List verification requests with optional filters. Returns paginated results.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| status | No | Filter by status. 'active' = live (not-yet-expired) pending or partial requests; persisted statuses are time-aware. | |
| reference_id | No | Filter by reference ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes | Pagination info in list responses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations supply readOnlyHint=true, and the description adds real operational context beyond that: paginated responses and the hard prerequisite of a Proof account with PROOF_API_KEY set and a server restart. It does not disclose default/max page size or what happens when filters match nothing, but the access profile is well covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with purpose then result shape then the access gate, with no filler. The ACCESS block is slightly imperative-heavy but every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists and pagination and auth are covered, so return values and setup are adequately handled. The gap is disambiguation: with an extremely dense sibling set of request/verification list tools, leaving the reader to infer scope (own requests? incoming? all?) is a material omission.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the non-obvious 'active' vs persisted status semantics, so the schema does the heavy lifting. The description only says 'optional filters' and adds no meaning beyond what the four documented parameters already carry; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List verification requests') plus result shape ('paginated results'). It does not distinguish itself from near-identical siblings in a crowded namespace (list_verifications, list_my_requests, list_incoming_requests, get_request_by_reference), so an agent cannot be certain which list to reach for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a genuine when-not: it explicitly says start_login does NOT open this tool, saving a doomed login round-trip. However, it names no alternative tool and gives no criteria for choosing between this and the many other verification-listing siblings, so routing guidance is partial.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_verificationsARead-onlyInspect
List verifications with optional filters. Returns paginated results.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| type | No | Filter by asset type | |
| limit | No | Items per page | |
| status | No | Filter by status | |
| channel | No | Filter by channel |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes | Pagination info in list responses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and the description adds value on top by disclosing pagination and a concrete auth prerequisite, including the non-obvious warning that start_login does not authorize this call. Missing rate-limit or result-volume context, but the auth/misconception disclosure is substantive beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The functional line is front-loaded and wastes nothing. The ACCESS block is longer than the purpose statement and reads as setup instructions, but every clause in it (account requirement, env var, restart) prevents a failed call, so it earns its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the auth prerequisite plus pagination note cover the operational essentials for invoking it correctly. The remaining gap is disambiguation from the many verification-adjacent siblings, which matters given the crowded namespace.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and three of the five parameters carry enums with documented values, so the schema already carries parameter meaning. The description only restates that filters are optional and results are paginated, adding no syntax, defaults, or interaction details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List verifications") plus the two defining traits: optional filters and paginated output. However, with siblings such as list_verified_users, list_verification_requests, list_reissued_proofs and list_revoked_proofs, it never clarifies which population of 'verifications' this returns, leaving the agent to infer the distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives one real usage condition (a Proof account with PROOF_API_KEY configured, and the explicit note that start_login does not unlock this tool), which is genuinely helpful. But there is no guidance on when to choose this over the numerous other list/get verification tools, so selection still requires inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_verified_usersARead-onlyInspect
List verified users grouped by external_user_id. Shows all verifications per user.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| pagination | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, so the bar is lower, and the description still adds non-obvious context: results are grouped rather than flat, and the tool is gated behind an API key that requires a server restart. The restart requirement in particular is behavior an agent cannot learn from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, front-loaded with what the tool returns before the access caveat. Wording is tight, though the instruction to "restart this server" is slightly awkward as a tool description rather than a doc note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return shape needn't be described, and the grouping semantics plus auth prerequisite fill the main gaps. The only missing piece for a list tool in a dense sibling set is explicit routing guidance versus the other verification-listing tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (page, limit) carry their own descriptions and bounds, so the schema does the heavy lifting. The description adds nothing about pagination behavior or default page size, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List verified users") plus a distinctive shaping detail: results are grouped by external_user_id with all verifications per user. That distinguishes it from get_verified_user (singular) and list_verifications, though it never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS paragraph gives a real prerequisite (a Proof account, PROOF_API_KEY set, server restart) and preempts a likely wrong turn by saying start_login does NOT open this tool. However, there is no guidance on when to choose this over list_verifications, get_verified_user, or list_verification_requests, so the selection logic among siblings is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_webhook_deliveriesARead-onlyInspect
List webhook delivery attempts with pagination and filtering. Shows delivery status, response codes, and timestamps.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number | |
| limit | No | Items per page | |
| status | No | Filter by delivery status | |
| event_type | No | Filter by event type (e.g. verification.completed) | |
| profile_id | No | Only this sub-account's deliveries | |
| endpoint_id | No | Only deliveries to this webhook endpoint | |
| verification_request_id | No | Only deliveries for this verification request |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | |
| pagination | Yes | Pagination info in list responses |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds genuinely useful context beyond that: the tool requires a Proof account with PROOF_API_KEY set and a server restart, and explicitly warns that start_login will not unlock it. It does not state default page size or ordering, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs, with the core capability front-loaded and the access requirement clearly separated. No filler sentences, though the blocking warning could be tightened into one line.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, 7-param list tool with a full schema and an output schema, the description covers capability, filters, returned fields, and the authentication prerequisite. Only the absence of ordering/default-pagination behavior keeps it from complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with every filter (status enum, event_type, profile_id, endpoint_id, verification_request_id) already documented in the schema. The description only restates that pagination and filtering exist, adding no semantics beyond the structured fields, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List webhook delivery attempts") plus the fields returned, so it is distinguishable from get_webhook_delivery (singular) and list_webhook_endpoints. It does not explicitly name those siblings as alternatives, which keeps it short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the name and the access note, but there is no guidance on when to use this versus get_webhook_delivery for a single attempt, get_webhook_stats for aggregates, or retry_webhook_delivery. The ACCESS paragraph is a prerequisite, not a when-to-use rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_webhook_endpointsARead-onlyInspect
List the account's webhook endpoints (URL, events, scope, sub-accounts, status). Secrets are never listed. A sub-account key sees only the endpoints scoped to exactly its own sub-account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description adds two substantive behavioral facts beyond that: secrets are redacted from results, and a sub-account key sees only endpoints scoped to exactly its own sub-account. The auth/restart requirement is also spelled out. It does not mention ordering, result limits, or pagination for what could be a long list, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences of substantive content up front, then a clearly separated ACCESS block that is front-loaded with the prerequisite. The access paragraph is somewhat verbose boilerplate ("Set PROOF_API_KEY and restart this server, then call this tool again"), but every sentence carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with an output schema already describing return values, the description covers the remaining risks: auth gating, secret redaction, and scope-based visibility. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. The description correctly avoids inventing filtering options that the empty schema does not support.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ("List the account's webhook endpoints") and even enumerates the fields returned (name, color-adjacent details, subdomain... specifically name, URL, subdomain... concretely: URL, events, scope, sub-accounts, status), so the agent knows exactly what comes back. It never names a sibling such as get_webhook_endpoint or list_webhook_deliveries, so the list-vs-get distinction is left to inference rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a real precondition for use (a Proof account with PROOF_API_KEY configured) and an explicit exclusion: "start_login does NOT open this tool," which steers the agent away from a plausible wrong path. It stops short of naming alternatives like get_webhook_endpoint for a single endpoint or list_webhook_deliveries for delivery history.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
poll_chat_id_discoveryARead-onlyInspect
Poll a chat ID discovery token. Returns the discovered Telegram chat ID, user ID, and username once the user interacts with the bot.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | Discovery token from create_chat_id_discovery |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | No | |
| chat_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description adds substantive behavior beyond that — the token resolves only after the user interacts with the bot, an auth prerequisite exists, and there is an explicit constraint that the link/text must appear in the agent's reply rather than only in tool output. It stops short of saying whether the call blocks or returns an empty status while pending.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, followed by the user-visibility caveat and then the access prerequisite, with no filler. The access paragraph is procedural but genuinely necessary since the tool is unusable without it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema covers return values, so the description needn't enumerate them, and it still summarizes them. Between the auth prerequisite, the pending-until-interaction semantics, and the user-visible-output warning, an agent has what it needs to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single token parameter is fully documented in the schema (100% coverage, sourced from create_chat_id_discovery). The description adds nothing about token lifetime or what happens when a token is expired or reused, so this is baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Poll a chat ID discovery token") and names what comes back (chat ID, user ID, username). It does not, however, distinguish itself from the closely named sibling wait_for_chat_id_discovery, which an agent could easily confuse with it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real context: use it for a challenge you created, and it requires a Proof account with PROOF_API_KEY set. But it never says why to poll instead of calling wait_for_chat_id_discovery, which is the most likely selection decision an agent faces here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
preview_templateARead-onlyInspect
Preview a template with sample data before saving, as a sub-account would send it. Shows how the message will look with placeholder variables filled in.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Template body text | |
| channel | Yes | Message channel | |
| subject | No | Email subject line | |
| profile_id | No | The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key | |
| button_text | No | Button text | |
| message_type | Yes | Message type | |
| button_url_template | No | Button URL template |
Output Schema
| Name | Required | Description |
|---|---|---|
| preview | No | |
| is_valid | No | |
| warnings | No | What a save would warn about; never makes `is_valid` false. Always sent; absent from an API that predates it. |
| validation_errors | No | What a save would refuse. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description is consistent with readOnlyHint=true — previewing implies no persistence. It goes meaningfully beyond the annotation by disclosing an authentication prerequisite (a Proof account plus PROOF_API_KEY set with a server restart) and by explicitly warning that start_login does Not satisfy that requirement, which would otherwise be a likely agent mistake.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and the timing condition come first in one tight sentence, followed by a rendering-behavior sentence and a separated access note. The access block is slightly verbose but is operationally necessary, and no sentence is pure filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the definition covers purpose, timing, and the auth gate for a 7-parameter read-only tool. The one real gap is the unresolved overlap with render_template, which an agent cannot resolve from this text alone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and two parameters carry enums, so the schema already carries the parameter burden; the baseline of 3 applies. The prose adds only marginal meaning — 'as a sub-account would send it' hints at profile_id semantics and 'placeholder variables' hints at button_url_template — without documenting any parameter directly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Preview a template with sample data') and clarifies the rendering semantics ('placeholder variables filled in', 'as a sub-account would send it'). It is immediately clear this is a non-persisting render preview, though it never distinguishes itself from the sibling render_template.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'before saving' gives a concrete temporal context that selects this tool over the mutation siblings (update_template, create-style flows). However, no exclusion is stated, and the near-identical sibling render_template is never mentioned, leaving the agent to guess between the two.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
regenerate_api_keyADestructiveInspect
Regenerate an API key: issues a new key (a new id and secret) with the same name, environment, scopes and sub-account. The old key stops working immediately; use the id in this response from now on. The new key lists the old one in replaced_key_ids, so its requests and usage stay with it. The new secret is returned ONLY in this response. Note: the secret will be visible in the AI conversation context.
Agent usage: This operation requires 2FA. Before calling, complete the 2FA flow: (1) call start_2fa with action_type "api_key_regenerate", (2) wait for user to verify the code, (3) poll get_2fa_status until "verified", (4) then call regenerate_api_key.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | API key ID to regenerate |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| key | Yes | The full API key. Returned only in this response; it cannot be read again. |
| name | Yes | |
| prefix | Yes | |
| scopes | Yes | |
| warning | Yes | |
| created_at | Yes | |
| profile_id | Yes | Sub-account (PublicProfile) the key is bound to; null for unbound keys. |
| environment | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the destructiveHint=true annotation: it discloses that the old key stops working immediately, that the new key's id supersedes the old, that replaced_key_ids links the two so requests and usage carry over, and that the secret is shown only once and will be visible in the AI conversation context. These are exactly the irreversible-side-effect and secret-exposure facts an agent needs before committing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core effect (new key issued, old one dies) before the secondary details, and the numbered 2FA steps are operationally necessary rather than filler. It is somewhat dense with four distinct fact blocks, but each sentence carries non-redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is unnecessary; the description instead covers the parts structured data cannot: irreversibility, one-time secret exposure, key-lineage behavior, 2FA sequencing, and authentication prerequisites. Nothing an agent needs to invoke this safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is documented as "API key ID to regenerate", so the baseline is already met; the description adds the useful clarification that this is the OLD key's id and that the response returns a new id to use going forward, which prevents passing the newly issued id back in.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (regenerate) and resource (API key) and immediately defines the semantics: a new id and secret with the same name, environment, scopes and sub-account. That behavioral footprint distinguishes it from siblings like create_api_key and revoke_api_key without naming them, since neither of those preserves identity/settings this way.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit, ordered prerequisite flow (start_2fa with action_type "api_key_regenerate", user verifies, poll get_2fa_status until "verified", then call this tool) plus account/access setup via PROOF_API_KEY or start_login. What is missing is guidance on when to regenerate versus create a fresh key or revoke an existing one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_circle_memberADestructiveInspect
Remove a member from a Circle. Deletes the member's channels and revokes any live authorizations that routed through them.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| member_id | Yes | Member ID to remove |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, but the description goes further by specifying exactly what is destroyed: the member's channels are deleted and live authorizations routed through them are revoked. It also discloses the auth prerequisite and its operational remedy, which no structured field provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and its side effects in two tight sentences, then separates the access requirement into a clearly marked block. The restart instruction borders on operational noise but is actionable for resolving the failure, so it largely earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values need no explanation. For a destructive, cascading removal with an authentication gate, the description covers the mutation, its blast radius, and the prerequisite — everything an agent needs to call it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Both parameters are fully described in the schema (100% coverage) as Circle ID and Member ID, so the schema does the heavy lifting. The description implies the member's channels are scoped to that member but adds no format, constraint, or identifier-matching detail beyond the schema, making the baseline 3 correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Remove a member from a Circle') and immediately clarifies scope by naming the cascading effects on that member's channels and authorizations. This is distinguishable from siblings like add_circle_member and remove_circle_member_channel without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition for use (requires a Proof account via PROOF_API_KEY and server restart) and preempts a likely wrong path by stating that start_login does NOT unlock this tool. It does not name sibling alternatives such as removing only a channel, but the context for when this tool applies is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_circle_member_channelADestructiveInspect
Remove a channel from a Circle member. Removing the last channel is allowed (the member simply becomes unreachable).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| member_id | Yes | Member ID | |
| channel_id | Yes | Channel ID to remove |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, but the description adds non-obvious behavior: the last channel may be removed and the member is then unreachable, and the call requires PROOF_API_KEY plus a server restart. That auth/environment prerequisite is information the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks with the action first and access requirements second; every sentence carries information. The ACCESS block is slightly verbose but justified by the hard prerequisite it communicates.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description covers the action, its edge-case effect, and the authentication gate. What remains missing is only the explicit sibling comparison (add vs remove vs list channels), a minor gap for a three-ID mutation tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and all three IDs (circle, member, channel) are documented in the schema with patterns, so the description adds no parameter-level meaning beyond it. Baseline 3 applies since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Remove a channel from a Circle member.' An agent can immediately tell this is the inverse of add_circle_member_channel and distinct from remove_circle_member, though neither sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a concrete edge-case rule ('Removing the last channel is allowed') plus the consequence, and explicitly warns that start_login does not unlock this tool, routing the agent away from a plausible wrong path. It stops short of naming the add/list channel siblings as alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_emailADestructiveInspect
Remove an email address from the account. Always requires one code: start_2fa_for_action with action_type email_remove and targets [this email id]. Revokes every proof of the address and your own consents naming it, declines pending confirmations waiting on it, moves Lookalike Watch alerts to your remaining primary email (or stops the watch when none is left), deletes the record, signs out your other devices, and names the new primary email. Refused for the address you signed in with and for your only way to sign in. Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Email record ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| type | No | |
| notice | No | |
| success | No | Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major. |
| identifier | No | Masked. |
| removed_id | No | |
| new_primary | No | The row that becomes (or became) primary when the removed one was; null otherwise. |
| proofs_revoked | No | |
| lookalike_watch | No | |
| circles_repointed | No | Phones only: circles that now reach the owner at `new_primary`; 0 for an email. |
| sessions_signed_out | No | Every other device was signed out, idle ones included; the calling session stays. False when that could not be done — the removal itself still happened. |
| sessions_invalidated | No | Other listed devices signed out, idle ones included; the calling session stays. A device missing from the list — signed in before the list held idle devices, or one whose listing could not be recorded — is not counted, so read `sessions_signed_out` for whether every other device was signed out. |
| authorizations_revoked | No | |
| hitl_configs_without_approver | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructive/non-read-only; the description goes far beyond by enumerating the cascade: revoking every proof and consent naming the address, declining pending confirmations, moving Lookalike Watch alerts to the remaining primary (or stopping the watch), deleting the record, and signing out other devices. It also states the operation cannot be undone and tells the agent which email becomes primary afterwards.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The action and its mandatory 2FA prerequisite are front-loaded in the first two sentences, followed by cascade effects and refusal conditions; the access note is separated at the end. Every clause carries distinct operational information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive single-parameter tool with an output schema, the description covers prerequisites, side effects, refusal cases, irreversibility, and authentication setup (PROOF_API_KEY or start_login). Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and already documents 'Email record ID', so the baseline is 3. The description adds value by tying the id to the required start_2fa_for_action targets and by constraining which ids are invalid (sign-in address, sole sign-in method), which the schema does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Remove an email address from the account') and implicitly separates itself from siblings such as set_primary_email, start_add_email, or revoke_proof by naming the exact record it deletes. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prerequisite ('Always requires one code: start_2fa_for_action with action_type email_remove and targets [this email id]') with the exact sibling tool and arguments to call first. It also names when the tool refuses ('the address you signed in with', 'your only way to sign in'), which is exactly the exclusion guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_phoneADestructiveInspect
Remove a phone number from the account. Always requires one code: start_2fa_for_action with action_type phone_remove and targets [this phone id]. Revokes every proof of the number and your own consents naming it, declines pending confirmations waiting on it, flags approval setups left with no approver, deletes the record and its messenger links, signs out your other devices, and names the new primary phone — your Proof of Me circles then reach you there. Refused for the number you signed in with, for your only way to sign in, and for your last phone while circles are active (circles_need_phone: add another phone first, or archive the circles). Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Phone record ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| type | No | |
| notice | No | |
| success | No | Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major. |
| identifier | No | Masked. |
| removed_id | No | |
| new_primary | No | The row that becomes (or became) primary when the removed one was; null otherwise. |
| proofs_revoked | No | |
| lookalike_watch | No | |
| circles_repointed | No | Phones only: circles that now reach the owner at `new_primary`; 0 for an email. |
| sessions_signed_out | No | Every other device was signed out, idle ones included; the calling session stays. False when that could not be done — the removal itself still happened. |
| sessions_invalidated | No | Other listed devices signed out, idle ones included; the calling session stays. A device missing from the list — signed in before the list held idle devices, or one whose listing could not be recorded — is not counted, so read `sessions_signed_out` for whether every other device was signed out. |
| authorizations_revoked | No | |
| hitl_configs_without_approver | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far beyond the destructiveHint=true annotation: it enumerates every side effect (revoking proofs and consents, declining pending confirmations, flagging approval setups with no approver, deleting messenger links, signing out other devices, reassigning primary phone) and states irreversibility. It also documents the access/session requirement and the exact error code returned on refusal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then prerequisite, effects, refusals, and access note in a logical order, with no filler sentences. The effect sentence is extremely dense (seven clauses stacked), which slightly hurts scanability but every clause carries required information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive single-parameter mutation with an output schema available, the description covers purpose, required 2FA step, full blast radius, refusal cases with remediation, irreversibility, and auth setup. An agent has everything needed to invoke it correctly or decide not to.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single `id` is documented as 'Phone record ID'. The description adds meaning by specifying that this id is what gets passed as the target in the start_2fa_for_action step, clarifying how the value is consumed rather than just what it is.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Remove a phone number from the account') and is immediately distinguishable from siblings like remove_email, set_primary_phone, and list_phones. The scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition ('Always requires one code: start_2fa_for_action with action_type phone_remove') and enumerates refusal conditions including the circles_need_phone remediation path. It does not explicitly route to sibling alternatives (e.g. 'use set_primary_phone instead to change primary'), so it falls short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_auth_linkARead-onlyInspect
Render an authorization or verification URL as a clickable link followed by a scannable QR code inside a fenced code block. This is a local computation tool — no HTTP request is made. Its output comes back to you, not to the user: copy the link, and the QR block inside its fence, into your reply.
Agent usage: pass a LINK field from an earlier response — deep_link (create_session, create_chat_id_discovery always; start_login, create_account, start_2fa, start_2fa_for_action, start_add_phone on telegram/whatsapp ONLY, where on sms and email that field is empty or absent altogether and this tool rejects it either way), challenge.deep_link (create_verification, messenger channels only), or telegram_deep_link / whatsapp_deep_link.
Do NOT pass qr_text to this tool: that field is a QR code already rendered as text, and this tool takes a link. When a response gives you qr_text and no link, print it verbatim inside a fenced code block instead — its rows only scan while they stay adjacent, so a blank line or wrapped row destroys the code.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | The link to render — e.g. a deep_link response field. Never a qr_text value: that is the link already rendered as QR art. | |
| label | No | Optional label to display above the link (e.g. "Verify your phone number") |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint; the description adds genuinely new behavior: it is a local computation with no HTTP request, the output returns to the agent rather than the user, and clients fold the result away so the link must be copied into the reply. That is exactly the operational context an agent cannot infer from the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the dense parenthetical field list earns its length by preventing wrong-input calls. The final paragraph about user visibility is slightly tangential to rendering but is load-bearing for correct overall usage.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain what comes back — and it does, including format (link plus QR inside a fence) and where it goes (agent, not user). Combined with the QR adjacency warning, nothing an agent needs to call and use it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description goes further by identifying the legitimate sources of `url` and stating that qr_text values are actively rejected — real semantic guidance beyond the schema. `label` is left to the schema, keeping it from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a concrete verb and resource — render an authorization/verification URL as a clickable link plus QR code in a fenced block — and immediately scopes it against sibling render_template-style tools by naming the input type. An agent can distinguish it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It enumerates exactly which upstream fields to pass (deep_link with per-channel caveats, challenge.deep_link, telegram_deep_link, whatsapp_deep_link) and explicitly excludes qr_text, with the alternate action (print qr_text verbatim in a fence) spelled out. When-to-use, when-not-to-use, and the fallback are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_templateARead-onlyInspect
Render the template a sub-account sends — its custom template, otherwise the default — with provided variables. Returns the fully rendered message content.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Message channel | |
| variables | No | Variables to substitute into the template | |
| profile_id | No | The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key | |
| message_type | Yes | Message type |
Output Schema
| Name | Required | Description |
|---|---|---|
| rendered | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, matching a pure render operation, so no contradiction. The description adds real operational context beyond annotations: the account/key prerequisite and the explicit false-lead about start_login. It stops short of disclosing side-effect claims (whether rendering is purely local vs billed), failure behavior for missing template variables, or fallback behavior when no custom template exists beyond the single clause already given.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact paragraphs: the first front-loads what the tool does and its return, the second front-loads the access prerequisite. Every sentence carries information, and the blunt 'start_login does NOT open this tool' is an efficient way to prevent a common misstep. Minor cost is that the access block is somewhat shouty and formatted apart from the core behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description correctly does not re-explain return structure while still noting that fully rendered message content comes back. For a read-only render operation with fully documented parameters, the only material extras — the account prerequisite and the start_login caveat — are both present, leaving nothing an agent needs in order to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so channel's enum, variables' nested fields, and profile_id's 24-hex pattern and default-resolution rule are already documented in the schema. The description adds only the general idea that variables are substituted into the template, which the schema's 'Variables to substitute into the template' already implies. The underspecified message_type parameter ('Message type', no enum) is not clarified in the description either.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource (render a template) and adds important resolution semantics: the sub-account's custom template is used, falling back to the default. It also clarifies that the tool returns rendered content rather than sending it, which separates it from send-style operations, though it never names the close sibling preview_template, so the render-vs-preview boundary is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a genuine usage precondition (a Proof account plus PROOF_API_KEY, and the explicit note that start_login does not unlock this tool, which prevents a wasted call). However, it offers no guidance on when to choose render_template over preview_template, get_template, or list_templates, so the routing decision among template siblings is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
request_hitl_authorizationAInspect
Request authorization for a HITL config. Sends consent requests to all configured channels (Telegram/WhatsApp). Users must approve before confirmations can be sent.
Agent usage: This must be completed before create_confirmation will work for this HITL config. The consent request is DELIVERED to each channel — the response carries no link to show. It returns authorizations — one entry per resolved recipient, each with its channel, recipient, authorization_id and status — plus a message. Read the entries rather than assuming: status: 'pending' means consent was just sent and the user must approve in Telegram/WhatsApp itself, while status: 'active' means that recipient had already authorized and nothing was sent to them. An EMPTY array does not mean everyone is authorized — it means no recipient could be resolved at all (usually a HITL config bound to a missing or inactive circle, or channels whose recipient is blank), so nobody was asked and waiting for an approval would hang forever. Do not relay message on that branch: it reads 'All channels already have active or pending authorizations', which is exactly the wrong conclusion. Read the array. After requesting, you can proceed once the user confirms they have approved.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | HITL config ID to request authorization for |
Output Schema
| Name | Required | Description |
|---|---|---|
| hitl_id | Yes | MongoDB ObjectId |
| message | Yes | |
| authorizations | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint=false/destructiveHint=false annotations: it discloses that the consent request is delivered to the channel with no link to show, describes the returned `authorizations` entries and the meaning of each `status`, and warns that an empty array means no recipient was resolved rather than universal authorization. It also documents the auth prerequisite (PROOF_API_KEY, restart required, start_login does not unlock it).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the operational warnings follow in a logical order, with no filler sentences. It is on the long side and the 'Read the array' directive partially restates the preceding empty-array warning, costing some tightness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite an output schema existing, the description supplies the interpretive layer the schema cannot: what each status value implies, why an empty array is not success, and that the accompanying `message` is misleading on that branch. Combined with the auth requirement, an agent has everything needed to call it and interpret the result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter and the schema already documents it at 100% coverage ('HITL config ID to request authorization for'). The description adds indirect context by mentioning HITL configs bound to missing or inactive circles, but contributes no new meaning about the `id` argument itself, so the baseline score applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Request authorization for a HITL config') and immediately states the observable behavior (sends consent requests to Telegram/WhatsApp). It also positions the tool relative to a sibling by declaring that it must run before create_confirmation works, so an agent can identify it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear prerequisite ('must be completed before create_confirmation will work') and a clear follow-up ('proceed once the user confirms they have approved'), which is exactly the when-to-use framing an agent needs. It stops short of distinguishing itself from the nearby create_authorization tool, which is the one plausible sibling ambiguity left unresolved.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resend_domain_emailAInspect
Resend the domain verification email. Rate limited to 3 requests per minute.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| email_prefix | No | Email prefix to resend verification to |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | Domain record |
| message | Yes | |
| email_sent_to | No | Sent when a code was sent; absent when the domain was already verified. |
| expires_in_minutes | No | Sent with `email_sent_to`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false, so the description adds real value: an explicit rate limit of 3 requests per minute and the authentication requirement (PROOF_API_KEY or a session via start_login). It does not say whether resending invalidates previously issued codes or changes domain state, which would be the remaining useful behavioral detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The operational sentence and rate limit are front-loaded, and the access precondition is clearly separated rather than buried. The ACCESS paragraph is slightly verbose in narrating the session flow, but every part conveys actionable setup information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity two-parameter action with an output schema already covering return values, the description covers what the tool does, its rate limit, and its auth prerequisites. The only gap is its relationship to the adjacent verification-start and code-confirm tools, which the description leaves unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, including a description for 'id' and an enumerated list of allowed email prefixes, so the schema does the heavy lifting. The description adds nothing about how 'id' or 'email_prefix' behave (for example, whether omitting the prefix defaults to admin). Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Resend the domain verification email', which is unambiguous about the operation. However, it does not distinguish this tool from closely related siblings such as resend_verification, start_domain_email_verification, or confirm_domain_email_code, so an agent must infer the distinction from names alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The implied trigger (the user did not receive the verification email) is clear enough from the verb 'resend', but it is never stated. There is no explicit guidance on when to prefer this over start_domain_email_verification or resend_verification, nor any exclusion conditions. The ACCESS block does give clear preconditions for invoking the tool, which partially compensates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resend_email_otpAInspect
Resend the OTP code for an in-progress email addition.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Add-email session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, and the description is consistent with that by implying an outbound send that changes state without destroying data. It adds useful auth and preconditions context, but omits key behavioral traits an agent needs for a resend tool: any cooldown/rate limit, which address the code goes to, and whether the previous code is invalidated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in one short sentence and the environment/access note is separated into its own labeled block. The ACCESS text is operationally verbose boilerplate, but it is clearly partitioned rather than buried mid-sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and auth prerequisites are covered. For a one-parameter resend operation, however, the definition leaves out resend-specific behavior (throttling, code supersession, transition to verify_email_otp) that an agent would need to call it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single session_id parameter is documented as "Add-email session ID," so baseline 3 applies. The description adds only indirect meaning via "in-progress email addition" and does not say where the session_id is obtained (start_add_email) or what happens if it is stale.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Resend the OTP code") scoped to "an in-progress email addition," which distinguishes it from start_add_email and verify_email_otp in the sibling list. It does not name those siblings explicitly, so the differentiation is inferable rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase "for an in-progress email addition" gives a clear triggering condition, and the ACCESS block explains the prerequisite path (PROOF_API_KEY or start_login). It stops short of stating when not to use it or pointing to verify_email_otp as the next step.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resend_verificationAInspect
Resend a verification message (email channel only). Generates and sends a new code.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | No | |
| expires_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only mark this as a non-read-only, non-destructive call. The description adds real behavioral context: a new code is generated and sent, the channel is restricted to email, and an account-level credential (PROOF_API_KEY) must be present before the call will work. It stops short of saying whether previously issued codes are invalidated or whether rate limits apply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The capability statement is front-loaded in the first sentence, and the access requirement is separated into its own block. Minor redundancy between "Resend a verification message" and "Generates and sends a new code," but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with an output schema and annotations, the description covers the action, channel constraint, and the non-obvious auth prerequisite. Only secondary details (prior-code invalidation, error behavior) are absent, which is acceptable given the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single `id` parameter is already documented as "Verification ID" in the schema. The description adds no format, sourcing, or lookup guidance for that id, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ("Resend a verification message") with a stated scope restriction ("email channel only") and an explanation of the side effect ("Generates and sends a new code"). It does not explicitly distinguish itself from close siblings such as resend_email_otp or trigger_verification, which keeps it short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The email-channel-only constraint and the access precondition imply when the tool is callable, but there is no explicit guidance on when to choose this over trigger_verification, create_verification, or resend_email_otp. Usage is implied rather than routed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retry_webhook_deliveryAInspect
Retry a failed webhook delivery. Creates a new delivery attempt with the same payload to the configured endpoint.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook delivery ID to retry |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| delivery_id | Yes | MongoDB ObjectId |
| next_retry_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false and destructiveHint=false; the description adds the key behavioral fact that the original delivery is not mutated but a new attempt is created with the same payload. It also discloses a hard auth prerequisite (PROOF_API_KEY, server restart) and explicitly rules out start_login as a workaround, which prevents a common wrong turn.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded in the first sentence and the second sentence explains the effect on the endpoint. The separate ACCESS block is clearly sectioned and earns its space by blocking a predictable failure mode, though it could be tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described, and the description covers the auth requirement and retry semantics well. Gaps remain around edge cases an agent would likely hit: what happens if the endpoint was deleted or disabled, and whether repeated retries are allowed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter has 100% schema coverage with its own description ("Webhook delivery ID to retry"), so the schema already does the work. The tool description adds nothing about where that ID comes from (list_webhook_deliveries) or its format, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Retry a failed webhook delivery") plus the mechanism ("Creates a new delivery attempt with the same payload to the configured endpoint"), which cleanly separates it from list_webhook_deliveries and get_webhook_delivery. It stops short of naming a sibling explicitly, so it lands just below the top mark.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The word "failed" implies the triggering condition, so usage is inferable, but there is no explicit when-to-use/when-not guidance and no pointer to alternatives such as get_webhook_delivery for first diagnosing the failure. The access note tells the agent to obtain credentials before calling, which is useful but is a prerequisite rather than usage selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_api_keyADestructiveInspect
Revoke an API key by ID. The key will immediately stop working. This action cannot be undone.
Agent usage: This operation requires 2FA. Before calling, complete the 2FA flow: (1) call start_2fa with action_type "api_key_revoke", (2) wait for user to verify the code, (3) poll get_2fa_status until "verified", (4) then call revoke_api_key.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | API key ID to revoke |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, and the description goes well beyond them: the key stops working immediately, the action is irreversible, 2FA is mandatory with a specific action_type, and a Proof account/session is required. Those are exactly the operational facts an agent needs before an irreversible mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded: consequence first, then prerequisites, then access. Sentences earn their place. The access paragraph is slightly muddled in its phrasing ("a session opens this tool"), which is the only reason this isn't a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and annotations cover the safety profile. The description fills the remaining gaps: gating requirements, the multi-step 2FA handshake, and the account prerequisite. Nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter 'id' is already documented as "API key ID to revoke", so the schema carries the meaning. The description only reinforces that revocation targets a key identifier and adds no format, source, or lookup guidance (e.g., obtain IDs from list_api_keys). Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Revoke an API key by ID") and immediately conveys scope through the irreversibility note. Against siblings like create_api_key, regenerate_api_key, list_api_keys, and get_api_key_usage, an agent can tell exactly which key-management operation this is without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit, numbered prerequisite sequence naming the exact sibling tools to call first (start_2fa with action_type "api_key_revoke", then get_2fa_status until "verified"). It also states the account/auth precondition. It does not say when NOT to use it (e.g., prefer regenerate_api_key when rotation rather than revocation is intended), which keeps it just under a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_assetADestructiveInspect
Revoke the proofs of one of your assets (a phone, email or domain) — the asset stays on the account. Owner only: sign in with start_login (a connection with only an API key is refused user_session_required — a key revokes a proof with revoke_proof instead), then one code: start_2fa_for_action with action_type revocation_bulk and targets [this asset id], wait_for_2fa, and call again. A phone or email: every proof of that number or address is revoked; signing in with it again issues a fresh proof. A domain you own: every proof of the domain and every delegation issued from it are revoked for good, and the domain needs re-verification — re-verifying does NOT bring the delegations back. Need a temporary stop for a domain proof? Use suspend_proof instead. Status-checking verifiers see the revocation within about a minute; signature-only verifiers accept a token until it expires. Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Asset ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| type | No | |
| notice | No | |
| outcome | No | `not_found` is also the answer for an asset the account does not own. |
| success | No | Always `true` |
| asset_id | No | |
| identifier | No | Masked for phones and emails; a domain travels in clear. |
| domain_status | No | Domains only: `reverification_required` — the domain stays on the account and needs re-verification before anything can be issued from it. |
| revoked_asset_ids | No | Every asset of the same identifier this call revoked with it, the named one included — a phone holds one asset per channel, a domain one per verification. |
| delegations_revoked | No | Domains only: the delegations revoked with the proofs. Re-verifying does not bring them back. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructiveHint=true; the description goes far beyond by disclosing what is destroyed per asset type (all proofs of a phone/email vs all proofs plus all issued delegations for a domain), that domain re-verification does not restore delegations, that the action is irreversible, and the propagation semantics (status-checking verifiers within ~1 minute, signature-only verifiers until token expiry). Auth failure modes (user_session_required) are also named.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and the 'asset stays' distinction are front-loaded, and the dense sentence packing (dashes, semicolons) keeps length proportional to a genuinely complex operation. It is a heavy read, but almost every clause carries operational information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full decision surface for an irreversible, owner-only mutation: required session state, the two-step 2FA protocol, per-asset-type consequences, alternatives, propagation timing, and re-verification caveats. An output schema exists, so return values need not be described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single `id` parameter, so the baseline is 3; the description adds meaning by explaining that the id may reference a phone, email or domain and that the resulting behavior differs materially by that type. It does not add format/syntax detail beyond that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with the specific verb+resource ("Revoke the proofs of one of your assets") and immediately clarifies the crucial scope distinction that the asset itself stays on the account — separating it from remove_phone/remove_email/delete_domain siblings. It also names revoke_proof as the differently-scoped alternative, so an agent can discriminate without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: use revoke_proof instead when authenticated with only an API key, use suspend_proof for a temporary domain stop, and the exact prerequisite chain (start_login, then start_2fa_for_action with action_type revocation_bulk, wait_for_2fa, then call again) is spelled out. When-not-to-use conditions are as clear as when-to-use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_authorizationADestructiveInspect
Revoke an active or pending authorization. Only authorizations with status "active" or "pending" can be revoked.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Authorization ID to revoke | |
| reason | No | Reason for revocation |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bsuid | No | WhatsApp Business-Scoped User ID |
| label | No | Owner-assigned human label for this approver (F22); null when unset. Surfaces lead with it, falling back to the masked recipient. |
| phone | No | |
| scope | Yes | Scope of the authorization. `identity_challenge` is the Proof of Me scope. |
| status | Yes | Status of an authorization |
| channel | Yes | Channel authorized for sending confirmations |
| hitl_id | No | |
| enrolled | Yes | Whether the approver has enrolled an encryption key. A confirmation can be sealed to an approver only once this is true; consent alone (`status: active`) is not enough. |
| circle_id | No | |
| denied_at | No | When the recipient refused — the mirror of `authorized_at` for a `denied` row (a challenger cancellation stamps it too). Absent unless the authorization was denied; before it existed such a row carried no decision time at all, only `updated_at`. |
| recipient | No | Channel-specific recipient identifier (chat_id for Telegram, phone or BSUID for WhatsApp) |
| created_at | Yes | |
| expires_at | Yes | |
| revoked_at | No | |
| updated_at | Yes | |
| proof_token | No | Signed proof of the recipient's decision, minted when they approved or refused, for both scopes. Absent while no decision has been made. |
| last_used_at | No | |
| authorized_at | No | |
| business_name | Yes | |
| verification_id | No | MongoDB ObjectId |
| revocation_reason | No | |
| confirmations_sent | Yes | |
| recipient_display_name | Yes | The approver's own messenger name ("First Last @username"), captured when they approved over Telegram; null when none was captured. Chosen by the approver, not verified. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=false and destructiveHint=true, the description adds the status precondition and concrete account, API-key, and server-restart requirements. It still omits whether revocation is irreversible, what capabilities it invalidates, and how attempts to revoke other statuses behave.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The action and eligibility rule are front-loaded, and the ACCESS label makes the setup guidance easy to scan. The first two sentences partially repeat the active/pending limitation, and the setup instructions could be slightly tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter destructive mutation with an output schema, the status restriction and access prerequisites cover most selection and invocation needs. Explaining revocation's consequences or permanence and providing an ID-discovery or related-tool pointer would make it more complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both id and reason already have clear descriptions, so the baseline score applies. The description adds no ID source or format and no guidance on when a revocation reason should be supplied.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Revoke an active or pending authorization" gives a specific action, resource, and eligibility scope. It does not explicitly distinguish this operation from related siblings such as revoke_delegation, revoke_proof, or cancel_verification_request.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The active/pending-only rule provides explicit when and when-not guidance, while the ACCESS section supplies prerequisites and warns that start_login is insufficient. It does not recommend an alternative for ineligible authorizations or point to list_authorizations or get_authorization for finding and checking an authorization.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_auth_sessionADestructiveInspect
Sign out one device (session) by ID. Over a signed-in session it cannot end the current one (that is logout). Over an API key it can end any of the account's sessions.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Session ID to revoke |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, and the description goes further by disclosing the exact blast radius under each auth mode (own current session excluded vs. any account session) and the access gating that must be satisfied first. This is behavior an agent cannot derive from the schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the operation and its scope constraint in the first sentence, followed by a clearly labeled ACCESS block. No filler sentences; every clause carries either scope or prerequisite information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with an output schema already describing returns, the description covers the two things an agent actually needs: what gets destroyed and under which credential, plus how to unblock access. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is already documented as 'Session ID to revoke'. The description only restates that identification is by ID, adding no format, sourcing, or enumeration guidance (e.g., where to obtain the ID, presumably list_auth_sessions). Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Sign out one device (session) by ID'), which cleanly separates it from list_auth_sessions, get_session, and create_session. It also carves out the one operation it is NOT (ending the current session, which is logout).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives the when-to-use boundary: over a signed-in session it cannot end the current session, over an API key it can end any of the account's sessions. It adds a concrete prerequisite (set PROOF_API_KEY and restart) and explicitly excludes the tempting alternative path ('start_login does NOT open this tool').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_delegationADestructiveInspect
Revoke ONE delegation. The domain control proof and sibling delegations stay valid; the revocation is mirrored into the proof registry so the CRL, status list and public status lookup all see it. Idempotent: a repeat revoke answers success with the same body, both here and through revoke_proof with the ph_dlg_ handle — unlike a PROOF, where a repeat answers already_revoked. The result carries the DERIVED effective_status/is_valid beside the stored status.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Delegation ID (24-hex Mongo id or ph_dlg_<32 hex> handle) | |
| reason | No | Reason for revocation |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| scope | No | Deprecated. Delegation schema 2.0 carries no scope; this array stays for the SDKs released before it: the scope a delegation issued before schema 2.0 was stored with, otherwise empty. Removed in the next major version. |
| status | No | The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on |
| delegate | No | Typed delegate identifier |
| is_valid | No | True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above |
| issued_at | No | |
| principal | No | The proven domain that authorized the delegate — derived from the control proof, never client input |
| created_at | No | |
| expires_at | No | Never later than the control proof's own expiry at issuance (effective expiry is min of the two) |
| revoked_at | No | |
| environment | No | |
| control_proof | No | The control proof handle this delegation points down to |
| delegation_id | No | Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint |
| revoked_reason | No | |
| effective_status | No | DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare destructiveHint=true; the description goes well beyond them by confirming collateral scope (domain control proof and sibling delegations survive), the downstream registry mirroring into CRL, status list and public lookup, and the idempotent repeat-revoke semantics that differ from PROOF revocation. It also repeats a prerequisite (Proof account) an agent must satisfy before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Effect and idempotency are front-loaded in the first two sentences, with access requirements properly separated into their own block. Slightly sprawling and parenthetical, but every sentence carries a distinct fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with an output schema present, the description covers blast radius, idempotency, prerequisite auth, and should-be-expected status fields, leaving no significant gap for an agent deciding whether and how to call it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are already documented, including the 24-hex / ph_dlg_ pattern and the reason enum. The description echoes only the ph_dlg_ handle form and adds no new meaning about what `reason` affects downstream, so it sits at the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb plus resource and scope ('Revoke ONE delegation'), and immediately distinguishes the blast radius ('the domain control proof and sibling delegations stay valid'), which is what separates it from revoke_proof in the sibling list. An agent can identify the target object and the exact effect without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states when this applies (revoking a single delegation, versus revoking a PROOF through revoke_proof with a ph_dlg_ handle) and gives an explicit exclusion: 'start_login does NOT open this tool', plus the PROOF_API_KEY prerequisite. That is exactly the when/when-not/alternative structure an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_proofADestructiveInspect
Revoke a proof by its public handle (ph_ctl_* / ph_dlg_*) or a verification ID — the same addresses get_proof_status takes. The proof token will no longer validate anywhere: the status endpoint, the public validator, the revocation list and the Token Status List all report it revoked. A domain CONTROL proof (a ph_ctl_* of a domain) also revokes, for good, every delegation issued from it; for a domain you own, every proof of the domain is revoked and the domain needs re-verification. The API key needs proofs:write, plus delegations:write while the revocation reaches live delegations — for a domain you own, any live delegation of the domain, whichever of its handles you name (the refusal names the scope and the count). A handle revoked before the domain was verified again does not reach the new proof: revoke that one by its own handle. Otherwise it revokes the PROOF only — the asset or consent it is about stays. Need a temporary stop? Use suspend_proof instead. Cannot be undone.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Public proof handle (ph_ctl_* / ph_dlg_*) or verification ID | |
| reason | No | Why the proof is revoked, one of: user_request, fraud, key_compromise, asset_transferred, other. A delegation proof (ph_dlg_*) refuses asset_transferred. The API refuses any other value. Defaults to user_request. |
Output Schema
| Name | Required | Description |
|---|---|---|
| reason | No | |
| success | No | |
| proof_id | No | Public proof handle (`ph_ctl_*`/`ph_dlg_*`). Present when the proof was addressed by handle. |
| principal | No | Control proofs only: the domain the proof is about. |
| proof_type | No | Which record carries the revoked proof (`verification`, `user_asset`, `verification_request`, `delegation`, …). Present when the proof was addressed by handle. |
| revoked_at | No | |
| owned_domain | No | Control proofs only: true when the account OWNS the domain (a Domain row or a domain asset for the name) and the whole-domain cascade ran — every proof of the domain and every delegation issued from it revoked, the domain demoted to `reverification_required`. False for a bare verification of somebody else's domain: that proof and the delegations anchored on it only. |
| domain_status | No | Control proofs only: the Domain row's status after the act (`reverification_required` after the cascade); null when the account has no Domain row for the name. |
| verification_id | No | Present only when the revoked proof belongs to a verification. |
| delegations_revoked | No | Control proofs only: the delegations revoked with the proof. Re-verifying the domain does not bring them back. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, and the description goes well beyond that: it lists every surface that will report the token revoked, states the cascade to live delegations and to all proofs of an owned domain, discloses the required scopes (proofs:write plus delegations:write) and the refusal's contents, and says plainly it cannot be undone. It stops short of describing the response body, but an output schema exists so that burden is lifted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and identifier space are front-loaded, and the alternative to suspend_proof is placed where an agent will read it. Every sentence carries information, but the middle section is a dense run-on covering cascades, scopes and refusals that would scan faster as separated clauses; length is defensible given the destructive, cascading behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, cascading operation this covers what an agent needs: what gets revoked, what survives (the asset or consent), the scope requirements, the refusal conditions, and the account/key prerequisite. Return values are handled by the output schema, so no gap remains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters already carry descriptions including the allowed reason values, so the baseline is 3. The description adds real meaning on top: it clarifies that the identifier space is shared with get_proof_status and warns that a handle revoked before re-verification will not reach the newer proof, which is a non-obvious invocation caveat.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ("Revoke a proof") and immediately narrows the accepted identifiers to public handles (ph_ctl_*/ph_dlg_*) or a verification ID, tying them to the same addresses get_proof_status takes. It distinguishes itself from suspend_proof by name, so an agent can tell the two apart without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit alternative with the condition that selects it: "Need a temporary stop? Use suspend_proof instead." It also spells out when the cascade path applies (domain CONTROL proofs, domains you own) and how to handle the re-verification edge case by revoking the new proof by its own handle.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rotate_callback_secretADestructiveInspect
Rotate a sub-account's callback signing secret — the secret that signs every callback_url delivery of its verification requests — and return the new one. This is the only time it is returned, so store it now. Callback deliveries already queued keep the secret they were signed with. An account still delivering through its settings webhook URL is switched over to webhook endpoints first.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | Yes | Sub-account (profile) ID, 24 hex characters |
Output Schema
| Name | Required | Description |
|---|---|---|
| secret | No | Signs every `callback_url` delivery of this sub-account's verification requests (`X-Proof-Signature`). |
| profile_id | No | The sub-account (`PublicProfile._id`) whose secret this is |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true; the description adds substantial behavior on top: the secret is returned exactly once and must be stored immediately, already-queued deliveries retain the secret they were signed with, and the call performs a side effect by migrating a settings-webhook-URL account to webhook endpoints. These are exactly the operational facts an agent needs before invoking a destructive rotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The one-time return warning is front-loaded right after the purpose, which is the correct ordering, and the side-effect note follows. The ACCESS block is essential rather than filler. A small amount of compression is possible but nothing is genuinely wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter mutation with an output schema, the description covers auth prerequisites, the one-time secret return, and the queue/migration side effects. It stops short of saying whether the old secret remains valid for newly generated deliveries or whether any propagation delay applies, which would matter in a rotation workflow.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single required profile_id, so the schema already carries the definition (24 hex characters). The description adds only the framing of that ID as a sub-account, matching but not extending the schema, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Rotate a sub-account's callback signing secret') and defines precisely which secret is meant (one used to sign every callback_url delivery). It implicitly separates itself from the sibling rotate_webhook_endpoint_secret by scoping to the sub-account, but never names that sibling, so an agent must infer the distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage context is clear: rotate when you need a new signing secret, and an account still using the settings webhook URL is migrated to webhook endpoints first. It also states the access prerequisite (Proof account, PROOF_API_KEY, restart the server) and explicitly rules out start_login as a path. The only gap is that it does not explicitly route per-endpoint rotation to rotate_webhook_endpoint_secret.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rotate_webhook_endpoint_secretADestructiveInspect
Replace a webhook endpoint's signing secret and return the new one — this and create_webhook_endpoint are the only times a secret is returned, so store it now. New deliveries are signed with the new secret; deliveries already queued keep the secret they were queued with.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook endpoint ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| url | No | HTTPS URL deliveries are POSTed to, at most 2000 characters. Private, loopback and link-local addresses are refused. |
| scope | No | `all` — every sub-account, present and future, plus account-level events. `selected` — only the sub-accounts in `profile_ids`; account-level events never reach it. |
| events | No | |
| legacy | No | The endpoint converted from the account's single webhook URL — the one the deprecated `/me/settings` webhook block reads and writes. |
| secret | No | The signing secret — returned only in this response. Store it now. |
| status | No | A `disabled` endpoint receives nothing; its history and secret are kept. |
| created_at | No | |
| secret_set | No | Whether the endpoint has a signing secret (always true). |
| updated_at | No | |
| description | No | |
| profile_ids | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, and the description goes well beyond that by explaining rotation semantics: new deliveries are signed with the new secret while already-queued deliveries retain their original secret. It also flags the one-time secret exposure and the account/auth prerequisite, which is exactly the extra context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and its consequence are front-loaded in the first sentence, with rotation timing and access requirements following. The ACCESS paragraph is a little verbose, but each sentence carries actionable information rather than restating the name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, credential-rotating operation the description covers the action, the irreversible consequence for queued deliveries, the one-time secret exposure, and the auth setup requirement. With an output schema present, return-shape detail is not needed, so nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'id' parameter is already documented as a 24-hex webhook endpoint ID. The description adds nothing about the parameter's format or source, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first clause gives a specific verb and resource: replace a webhook endpoint's signing secret and return the new one. It also implicitly scopes itself apart from create_webhook_endpoint, but never distinguishes itself from the sibling rotate_callback_secret or update_webhook_endpoint, which an agent could easily confuse with it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear situational context — that this is one of only two calls that ever return a secret, and that the secret must be stored immediately. It does not, however, state when an agent should rotate rather than use rotate_callback_secret or update_webhook_endpoint, so the alternative-selection guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchARead-onlyInspect
Prefix-anchored global account search across six resource buckets (verification_requests, verifications, hitl, confirmations, authorizations, api_keys). Case-sensitive prefix match over indexed plaintext fields only; recipient identifiers are masked. Results are scoped to the authenticated account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | Prefix-anchored search query (minimum 3 characters) | |
| type | No | Narrow the search to a single result bucket | |
| limit | No | Max results per bucket (default 10, max 25) | |
| environment | No | Scope results to test or production data (default: production) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| total | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses real behavioral traits: matching is case-sensitive and prefix-anchored (not substring), only indexed plaintext fields are searchable, recipient identifiers come back masked, and corrects an easy assumption by stating start_login does not unlock this tool. It does not describe result ordering or the empty-result case, which keeps it off a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs with the capability statement front-loaded and the access prerequisite separated out, so an agent can read the first line and act. The uppercase ACCESS header is functional rather than filler, though the setup instructions are somewhat verbose relative to the search semantics.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter read tool with an output schema, full annotation of read-only behavior, and complete schema coverage, the description covers everything an agent needs: what is searched, matching rules, masking of sensitive fields, account scoping, and the authentication prerequisite that otherwise would cause repeated failed calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents q, type, limit, and environment, and the description repeats the six enum values already present in the schema. It does add meaning for `q` by clarifying the matching is case-sensitive prefix rather than free-text, but adds nothing on limit or environment defaults. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names a specific verb and resource ("Prefix-anchored global account search") and enumerates the six buckets it covers, which lets an agent distinguish it from the many per-resource list_* siblings (list_verifications, list_confirmations, list_api_keys). The scope (account-wide, authenticated account only) is stated up front.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operating context: use it for prefix matching across all six buckets, and the `type` field narrows to one bucket. The ACCESS note explicitly rules out start_login as a path to enabling this tool, which prevents a plausible wrong turn. It stops short of explicitly stating when to prefer this over a specific list_* sibling when the bucket is already known.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_account_emailAInspect
Deliver the verification email for an account-bootstrap session created with channel "email". Public endpoint (no API key required).
Why this is a separate call: create_account deliberately sends NOTHING. A message from proof.holdings arriving in someone's inbox is an act with a person on the other end, so it takes an explicit second step rather than being a side effect of creating a session. ASK THE USER to confirm the address is theirs before calling this — do not call it automatically after create_account.
The other channels (telegram, whatsapp, sms) never need this: the user sends the first message themselves (reverse OTP), so nothing is dispatched to them at all.
One session sends at most one email, including under concurrent calls. A repeat answers 410 already_sent, which means the material backing the send is gone: usually because the email went out, occasionally because an attempt was interrupted mid-send and nothing was delivered. Do not tell the user a message was sent on the strength of a 410 — create a new session instead. (A session the recipient cancelled via the decline link, or an expired one, answers 404, not 410.) If delivery fails the response carries email_sent=false and the call can be retried.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Account session id from create_account |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| channel | No | |
| email_sent | No | |
| email_error | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false / destructiveHint=false, so the description carries most of the weight and delivers: an irreversible external send (a human receives mail), one email per session even under concurrency, 410 already_sent semantics, 404 for cancelled/expired sessions, and email_sent=false meaning retry is safe. It doesn't mention rate limits or auth-scope details beyond "public endpoint", but the failure-mode mapping is unusually rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the caller's confirmation obligation; the parenthetical about 404 vs 410 and the retry rule are load-bearing. The "Why this is a separate call" rationale paragraph is defensible design context but is the one part that could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still explains the error-status meanings and the email_sent flag that an agent must branch on. Combined with the preconditions, the caller has everything needed to decide whether and how to call it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is already documented as "Account session id from create_account", so baseline is 3. The description adds a qualifying constraint the schema lacks: the id must come from a session created with channel "email", and a consumed session cannot be reused.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Deliver the verification email") scoped to "an account-bootstrap session created with channel 'email'". It explicitly separates itself from create_account and from the other channel flows, so an agent can distinguish it from siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when: only after asking the user to confirm the address, and explicitly when-not: "do not call it automatically after create_account" and "the other channels never need this". It also names the sibling behavior it must not be conflated with.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_primary_emailBDestructiveInspect
Set an email address as the primary email for the account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Email record ID to set as primary |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the mutation risk is signaled structurally. The description adds genuine value with the authentication/session requirement, but it does not disclose what the destructive change actually entails — whether the previous primary is demoted or dropped, and whether the target address must be verified first.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with the core action front-loaded and the access requirement second; no filler. The ACCESS sentence is somewhat dense with two alternative authentication paths, but every clause is actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the auth prerequisite is covered. For a destructive account-level mutation, though, the definition leaves out key preconditions and side effects (verification state of the address, fate of the prior primary), which an agent needs before invoking it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter 'id' is documented as 'Email record ID to set as primary.' The description adds nothing about the identifier format or how to obtain it (e.g., from list_emails), so the baseline 3 applies when the schema carries the parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Set an email address as the primary email for the account.' An agent can immediately tell this is a mutation of the primary-email designation. It does not distinguish itself from nearby siblings such as list_emails, start_add_email, or set_primary_phone, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS sentence gives a real precondition (a Proof account plus either PROOF_API_KEY or a session via start_login), which is useful when-to-use context. However, it never says when to prefer this over start_add_email or verify_email_otp, nor what state the email must already be in, so the alternative-selection guidance is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_primary_phoneADestructiveInspect
Set a phone number as the primary phone for the account.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Phone record ID to set as primary |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so safety framing is covered. The description earns credit for disclosing what annotations cannot: the account/key requirement, the environment variable, and the sign-in-then-retry flow that otherwise would look like a failure. It loses a point for not saying what happens to the previously primary phone, which is the core destructive effect implied by destructiveHint=true.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two well-structured blocks: the action statement first, then a clearly labeled ACCESS note, so the core purpose is front-loaded. The access paragraph is slightly longer than needed and its 'a session opens this tool' clause is awkwardly worded, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter mutation with an output schema, annotations covering safety, and auth explicitly documented, almost everything an agent needs is present. The remaining gap is the side effect on the incumbent primary phone, which matters given destructiveHint=true on a 'set primary' operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with a single required parameter already documented as 'Phone record ID to set as primary'. The description adds no format example, no indication of where the ID is obtained, and no note on whether the ID is account-scoped. Baseline 3 is appropriate when the schema carries the full parameter burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Set a phone number as the primary phone for the account.' An agent can distinguish it from list_phones, remove_phone, and start_add_phone without ambiguity. It falls short of a 5 because it never explicitly names which sibling to use first (e.g., list_phones to obtain the record ID) or contrasts itself with the parallel set_primary_email / set_primary_profile tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives a real prerequisite: a Proof account via PROOF_API_KEY or an authenticated session through start_login, plus the notable retry pattern of calling the tool again after signing in. That is useful setup guidance, but it is auth logistics rather than when-to-use guidance — it never says when to prefer this over removing and re-adding a phone, nor that the id must come from list_phones.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_primary_profileADestructiveInspect
Set a profile as the primary profile. The previous primary profile becomes secondary.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| profile_id | Yes | Profile ID to set as primary |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bio | No | |
| theme | Yes | Profile theme customization |
| username | No | Absent until a username is claimed |
| is_public | Yes | |
| avatar_url | No | A URL or a data URI; null once cleared |
| created_at | Yes | |
| is_primary | Yes | |
| profile_id | Yes | The public id used in profile URLs |
| updated_at | Yes | |
| view_count | Yes | |
| email_theme | Yes | Theme of this sub-account's emails; null when unset (read as `dark`). |
| is_business | Yes | |
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| custom_links | Yes | |
| display_name | No | |
| business_name | No | |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
| support_email | Yes | Support address shown in this sub-account's messages; null when unset. |
| show_delegations | Yes | |
| verification_level | Yes | Always 'basic'; no levels are computed; removed in the next major. |
| show_proof_channels | Yes | |
| show_verification_dates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, and the description backs that up by stating the concrete consequence: the previous primary profile is demoted to secondary. It also discloses the authentication prerequisite and that start_login does not unlock this tool, which is context the annotations cannot express. It stops short of covering failure modes, e.g. whether the target profile must be verified or active.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences front-load the action and its side effect, followed by a clearly separated ACCESS block. No sentence is redundant or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter mutation tool with annotations and an output schema, the description covers action, side effect, and authentication prerequisites, which is most of what an agent needs. Missing only edge-case behavior such as preconditions on the target profile or what happens on invalid IDs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 100% schema description coverage ("Profile ID to set as primary"), so the schema already carries the semantics. The description adds nothing about format, source of the ID, or constraints, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ("Set a profile as the primary profile") and immediately describes the side effect. It is clearly distinguishable from neighboring tools such as update_profile, set_primary_phone, and set_primary_email.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than explained: it tells the agent which operation this performs but never names alternatives or the conditions that select it over update_profile or get_my_profile. The ACCESS paragraph does add a real precondition (a Proof account plus PROOF_API_KEY) and explicitly rules out start_login as a shortcut, which is valuable routing information.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
setup_domain_emailAInspect
Register a verified domain with Proof's email provider (Resend) for sending. The result carries the DKIM/SPF DNS records to publish (resend.dkim_records) and their status. from_email, if given, must be on this domain and is stored as the preferred sender. Proof does not send from customer domains yet: verification emails still come from Proof's own address, and the stored from_email is not used.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| from_email | No | Custom from email address for the domain |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say it is a non-read-only, non-destructive mutation; the description goes further by disclosing the auth requirement, that the response carries DKIM/SPF records and their status, and the non-obvious caveat that Proof does not yet send from customer domains so the stored from_email is unused. It does not say what happens on repeat registration or whether the call is idempotent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then the return payload, then the caveat, then access — a sensible order with no filler. The result-shape sentence is partly redundant given an output schema exists, which keeps it off a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation with an output schema, the description covers auth, the parameter constraint, and the surprising non-functional behavior of from_email. Remaining gaps are preconditions (does the domain need to be added first?) and post-call next steps (publish DNS, then verify), which a caller may need.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description earns above that by adding a real constraint absent from the schema: from_email must be on this domain and is stored as the preferred sender, but is currently unused. The id parameter is left to the schema's "Domain ID" label with no further qualification.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource ("Register a verified domain with Proof's email provider (Resend)") plus the effect ("for sending"), so an agent knows exactly what the call does. It doesn't explicitly name the sibling it is *not* (e.g. start_domain_email_verification or check_domain_email_status), so differentiation is inferential rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives concrete prerequisites and a recovery path (set PROOF_API_KEY and restart, or sign in via start_login then retry), which is real when-to-use guidance. It also warns that from_email is currently inert, preventing a mistaken use. It stops short of stating that a domain must first exist (the id param implies add_domain) or pointing to the verification siblings as the next step.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_2faAInspect
Start a two-factor authentication challenge for a sensitive operation. Sends a verification code via the chosen channel. Returns a session ID, and for messaging channels: deep_link, qr_code (base64 PNG), and qr_text (UTF-8 text QR for terminal display).
Agent usage — full 2FA flow: (1) Call start_2fa with the appropriate action_type and channel. (2) Present the challenge, and do NOT announce a message the server did not send: email is the ONLY channel it dispatches on. On telegram/whatsapp the user opens deep_link and sends the message themselves; on sms they send sms_message to a number from sms_dids; the response's own instructions field says which. On email, a 200 carrying requires_email_selection: true and available_emails means nothing was sent and no session exists — ask which address and call again with email_id. For telegram/whatsapp, pass deep_link to render_auth_link; for sms, show sms_message. Never hand qr_text to a link renderer — it is the link already rendered as QR art, so print it verbatim inside a fenced code block only when a real terminal needs the QR. (3) Poll get_2fa_status with the returned session_id until status is "verified" (the user enters the code on their device) or "expired". (4) If verified, proceed with the protected operation (e.g. create_api_key). If expired, inform the user and offer to restart. Typical channels: "telegram" or "email". For email, the user may receive a magic link instead of a code — the backend handles this automatically.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel to receive the verification code | |
| targets | No | The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the sub-account id; account_delete: your own user id (get_current_user). Leave out for the other action types. | |
| email_id | No | Specific email ID for email channel (optional) | |
| phone_id | No | Optional: specific UserPhone id for phone-channel 2FA | |
| single_use | No | Whether the grant is consumed on first use. Server forces true for destructive action types. Defaults to true. | |
| action_type | Yes | The sensitive action requiring 2FA: any action type the API documents | |
| ttl_seconds | No | Requested grant lifetime in seconds. Server caps to 300s for destructive action types, 86400s for configuration scopes. Defaults to 300 if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| No | The address the code went to, masked (`email` only) | |
| status | No | |
| channel | No | |
| message | No | |
| qr_code | No | Base64-encoded PNG QR code for `deep_link` |
| qr_text | No | UTF-8 text QR for `deep_link`, for terminal/agent rendering |
| sms_code | No | The short code the person texts (`sms` only) |
| sms_dids | No | Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code. |
| deep_link | No | Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`) |
| email_sent | No | `true` when the code was emailed (`email` only) |
| expires_at | No | |
| session_id | No | |
| sms_message | No | The message to send (`sms` only) |
| instructions | No | One line telling the person what to do |
| available_emails | No | The addresses the code may go to; call again with one of their ids as `email_id` |
| requires_email_selection | No | Always `true`: no session was started, pick an address and start again |
| second_method_recommended | No | Present (true) when the step-up uses the channel the account signed in with, because the account has no other; adding a second channel is recommended |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations only declaring non-read-only/non-destructive, the description supplies substantive behavior: dispatch only on email, user-sent messages on other channels, requires_email_selection meaning no session, polling until verified/expired, and user-visible output handling. This is well beyond annotation-level detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and then uses numbered steps and channel-specific notes; the structure is strong. It is long, but most of the length corresponds to genuine multi-channel flow complexity and edge cases.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex multi-step 2FA starter with an output schema, the description covers initiation, channel dispatch, polling handoff, expiration, access prerequisites, and user-facing caveats. Nothing essential to correct invocation appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents action_type, targets, single_use, ttl_seconds, and optional IDs. The description adds operational context for channel/email_id and the email-selection retry, but it does not add meaning for the remaining parameters; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb ('Start') and resource ('two-factor authentication challenge') and scope ('sensitive operation'). It also separates this tool's role from get_2fa_status by explicitly placing polling in step 3, so an agent can distinguish start from status-check.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a numbered full flow from start through polling and post-verification action, plus channel-specific handling for telegram/whatsapp/sms/email and the email-selection edge case. It names alternatives like get_2fa_status and render_auth_link, though it does not discuss start_2fa_for_action.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_2fa_for_actionAInspect
Start a 2FA challenge that grants the authenticated user permission to perform a sensitive action. The 2FA must complete on a channel DIFFERENT from the user's last login channel (the backend enforces this). On success a grant is stored keyed by the user id and action_type; middleware on the protected endpoint reads the grant and allows the mutation.
Destructive action types (api_key_create, api_key_revoke, api_key_regenerate, api_key_view, account_delete, phone_remove, email_remove, phone_primary, email_primary, revocation_bulk, domain_remove, profile_delete) are capped at 5min TTL and forced single-use by server policy. A step-up for revocation_bulk, phone_remove, email_remove, domain_remove, profile_delete or account_delete is bound to targets — the exact ids the protected call will carry. Configuration scopes (settings_write, profile_update, templates_write) allow up to 24h TTL and caller-chosen single_use — useful for agents making multiple settings mutations in one session.
Agent usage: (1) Attempt the sensitive call; if you get 403 2fa_required note the action_type. (2) Call start_2fa_for_action with that action_type and a channel different from the login channel. (3) Present the challenge: on telegram/whatsapp pass deep_link to render_auth_link; on sms show sms_message and the number to send it to; on email check the response first: with more than one verified email and no email_id given, it answers 200 with requires_email_selection: true and available_emails — NO session was started and nothing was sent, so ask the user which address and call again with email_id rather than telling them to open a mailbox. Never hand qr_text to a link renderer — it is the link already rendered as QR art. Print it verbatim inside a fenced code block only when a real terminal needs the QR. (4) Call wait_for_2fa until the session is verified. (5) Retry the original sensitive call.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel for the 2FA challenge — must differ from the user's last login channel | |
| targets | No | The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the sub-account id; account_delete: your own user id (get_current_user). Leave out for the other action types. | |
| email_id | No | Optional: specific UserEmail id for email-channel 2FA | |
| phone_id | No | Optional: specific UserPhone id for phone-channel 2FA | |
| single_use | No | Whether the grant is consumed on first use. Server forces true for destructive action types. Defaults to true. | |
| action_type | Yes | The sensitive action the 2FA grant will authorize: any action type the API documents. The server caps each by its policy: destructive types (e.g. api_key_*, *_remove, revocation_bulk, account_delete) to 5 min TTL and single use; configuration scopes (e.g. settings_write, webhook_write) up to 24h with caller-chosen single_use. | |
| ttl_seconds | No | Requested grant lifetime in seconds. Server caps to 300s for destructive action types, 86400s for configuration scopes. Defaults to 300 if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| No | The address the code went to, masked (`email` only) | |
| status | No | |
| channel | No | |
| message | No | |
| qr_code | No | Base64-encoded PNG QR code for `deep_link` |
| qr_text | No | UTF-8 text QR for `deep_link`, for terminal/agent rendering |
| sms_code | No | The short code the person texts (`sms` only) |
| sms_dids | No | Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code. |
| deep_link | No | Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`) |
| email_sent | No | `true` when the code was emailed (`email` only) |
| expires_at | No | |
| session_id | No | |
| sms_message | No | The message to send (`sms` only) |
| instructions | No | One line telling the person what to do |
| available_emails | No | The addresses the code may go to; call again with one of their ids as `email_id` |
| requires_email_selection | No | Always `true`: no session was started, pick an address and start again |
| second_method_recommended | No | Present (true) when the step-up uses the channel the account signed in with, because the account has no other; adding a second channel is recommended |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Well beyond the annotations, it discloses TTL caps by action class (5 min for destructive, up to 24h for configuration scopes), server-forced single_use, the channel-must-differ enforcement, the target_mismatch refusal, and the silent email-selection branch where no session is started. It also warns that tool results are folded away by most clients, which changes how the agent must surface the link or SMS text. The destructiveHint=false annotation refers to this tool, which only mints a grant, so the discussion of destructive action types is not a contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then policy, then the numbered agent workflow, so a reader can stop early. It is dense and long, and a few items are duplicated between description and schema (TTL caps, single_use forcing, targets binding), but nearly every sentence carries operational information an agent would otherwise get wrong.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter, policy-heavy step-up tool it covers everything that matters: auth prerequisite (PROOF_API_KEY, restart), the full call sequence, per-channel presentation, the email-selection edge case, and the qr_text pitfall. An output schema exists, yet it still clarifies the response fields that drive branching behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the bar is adding meaning: it does, by tying targets to the exact ids the protected call will carry (one code per asset for revocation_bulk, get_current_user for account_delete) and by explaining that single_use and ttl_seconds are overridden by server policy. Most of this restates the schema's own parameter descriptions, so the added value is real but partial.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Start a 2FA challenge that grants the authenticated user permission to perform a sensitive action,' plus the mechanism (grant keyed by user id and action_type, read by middleware). It clearly differs from the login-2FA siblings, but it never names start_2fa / verify_2fa / wait_for_2fa as the alternatives it is not, leaving the agent to infer the distinction from the action-bound framing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit five-step loop (attempt call, catch 403 2fa_required, start challenge, present it, wait, retry) with concrete alternatives per channel: render_auth_link for deep_link, sms_message for sms, and re-calling with email_id instead of telling the user to check a mailbox. It also states a hard exclusion: 'start_login does NOT open this tool.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_add_emailAInspect
Start adding a new email address. Sends an OTP code to the email. Returns a session ID to verify with.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Email address to add |
Output Schema
| Name | Required | Description |
|---|---|---|
| Yes | ||
| status | Yes | |
| channel | Yes | |
| email_sent | Yes | Whether the code went out; the session is started either way |
| expires_at | Yes | |
| session_id | Yes | |
| email_error | No | Why the code did not go out; present only when `email_sent` is false |
| instructions | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare this is a non-read-only, non-destructive mutation; the description adds the important behavioral facts beyond that — an actual OTP email is dispatched to the target address and a session ID is produced as the handle for the next step. It does not cover OTP expiry, retry/rate-limit behavior, or the existence of resend_email_otp, leaving some operational context unstated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded in the first two sentences and the access prerequisite is broken out as a separate labeled block, which is easy to scan. The ACCESS paragraph is slightly verbose for a precondition but each clause is actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description covers the two things an agent must know: authentication gating and the session-ID handoff to verification. Missing only edge-case behavior such as duplicate emails or OTP lifetime, which keeps it from a 5 for a flow-starting mutation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter with 100% schema coverage including a format and regex pattern, so the schema already carries the semantics. The description adds nothing about the email argument itself (e.g., deliverability or normalization rules), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Start adding a new email address') and adds two concrete behaviors: an OTP is sent and a session ID is returned for verification. This clearly separates it from sibling flows such as setup_domain_email, add_domain, or start_add_phone, though it never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a clear precondition chain: you need a Proof account, either via PROOF_API_KEY or by signing in with start_login, and it notes that a session opens this tool, so the agent knows to retry after login. It stops short of explicit exclusions (e.g., what to do if the email already exists) or naming the follow-up verification tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_add_phoneAInspect
Start adding a new phone number by reverse OTP: the user starts the exchange themselves and nothing is sent before they do; the response's instructions field says what they do (on telegram the bot then asks them to tap a button that shares their number). Returns a session ID; on telegram/whatsapp also deep_link, qr_code (base64 PNG) and qr_text (UTF-8 text QR), and on sms sms_message and sms_dids (one entry per region; a region with no number configured has an empty did) with no deep_link.
Agent usage: on telegram/whatsapp pass deep_link to render_auth_link for the link and a QR code. On sms there is no deep_link — show sms_message and a number from an sms_dids entry whose did is non-empty. Never hand a qr_text to a link renderer — it is a link already rendered as QR art. Then poll get_add_phone_status with the session ID.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel for phone verification |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | |
| channel | Yes | |
| qr_code | No | Base64-encoded PNG QR code for `deep_link` |
| qr_text | No | UTF-8 text QR for `deep_link`, for terminal/agent rendering |
| sms_code | No | The short code the person texts (`sms` only) |
| sms_dids | No | Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code. |
| deep_link | No | Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`) |
| expires_at | Yes | |
| session_id | Yes | |
| sms_message | No | The message to send (`sms` only) |
| instructions | Yes | One line telling the person what to do |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare non-read-only, non-destructive, which the description is consistent with. Beyond that it discloses the genuinely non-obvious behaviors: nothing is sent to the user before they act, results differ per channel (deep_link absent on sms), and clients fold tool output away so the agent must re-state the link/SMS text in its own reply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core mechanic, then returns, then agent usage, then the visibility caveat — a sensible ordering. Slight redundancy remains: "the user starts the exchange themselves and nothing is sent before they do" restates "reverse OTP", and "with no deep_link" is repeated in the agent-usage paragraph.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full loop an agent needs: what initiates the exchange, how to present credentials per channel, what to do afterwards, and the authentication prerequisite. Return fields are described even though an output schema exists, which is a surplus rather than a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter, and the schema already documents the channel enum, so the baseline is high. The description still earns credit by explaining what choosing each channel actually produces downstream (deep_link/QR vs sms_message plus regional DIDs), which is meaning the schema cannot carry.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+mechanism: "Start adding a new phone number by reverse OTP." It is clearly distinguishable from list_phones, remove_phone and the follow-up get_add_phone_status, and names the downstream sibling render_auth_link it feeds.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit per-channel playbook: pass deep_link to render_auth_link on telegram/whatsapp, show sms_message plus a non-empty sms_dids `did` on sms, then poll get_add_phone_status with the session ID. It also includes a negative instruction (never hand qr_text to a link renderer) and states the access prerequisite and two ways to satisfy it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_domain_email_verificationBInspect
Start domain verification via corporate email. Sends a verification code to a standard admin email address at the domain.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID | |
| email_prefix | No | Email prefix to send verification to (default: admin) |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | Domain record |
| message | Yes | |
| email_sent_to | No | Sent when a code was sent; absent when the domain was already verified. |
| expires_in_minutes | No | Sent with `email_sent_to`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only mark this as a non-readonly, non-destructive mutation, so the description carries the burden and does add value by disclosing the outbound side effect (an email is dispatched to an admin address) and the auth/session requirement. It stops short of stating whether repeat calls invalidate a prior code, whether rate limits apply, or what the caller should do after the email is sent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in two tight sentences, and the ACCESS block is clearly separated from the functional description. The access text reads as boilerplate and partly repeats itself ('Set PROOF_API_KEY and restart ... or sign in with start_login'), which keeps it just below top marks.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A return-shape explanation is not needed because an output schema exists, and the inputs are fully documented. The missing piece is workflow context: this is a step in an email-verification sequence, and with dozens of adjacent verification tools the description should say what happens next and which sibling confirms the code.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the enum of allowed prefixes and the 'admin' default, so the schema already does the heavy lifting. The description only reinforces that the recipient is a standard admin address at the domain and adds nothing about how the domain 'id' is obtained, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It states a specific verb and resource (start domain verification) plus the mechanism (a verification code mailed to an admin-address at the domain), so the action is unambiguous. However, it does not distinguish itself from closely named siblings such as start_domain_verification, start_user_domain_verification, or verify_domain, which an agent cannot disambiguate from this text alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives real prerequisites (Proof account, PROOF_API_KEY, or obtaining a session via start_login), which is useful. But it offers no explicit when-to-use/when-not guidance against the many alternative verification entry points listed as siblings, and does not point to the natural follow-up (check_domain_email_status / confirm_domain_email_code).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_domain_verificationAInspect
Start a B2B domain verification. Creates a verification record and returns DNS/HTTP instructions for the customer to complete.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain to verify (e.g. example.com) | |
| customer_id | No | Customer identifier for B2B tracking | |
| verification_method | No | Verification method (default: manual_dns) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| domain | No | |
| status | No | |
| provider | No | |
| http_file | No | |
| dns_record | No | |
| verification_method | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false and destructiveHint=false; the description adds that a record is created and that the caller should hand DNS/HTTP instructions to the customer, which is genuine behavioral context. The access/auth disclosure (Proof account plus API key restart) is exactly the kind of non-obvious gating the annotations cannot express. It still omits whether a verification can be re-started or what happens to an existing record.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, purpose first and access constraint second, with no redundant wording. The all-caps ACCESS line is a little blunt but front-loads the obstruction an agent would otherwise hit.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the 3-parameter schema is fully described, so the description only needs purpose plus prerequisites — both supplied. The remaining gap is disambiguation from the large family of sibling verification tools, which matters here given the crowding.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and every parameter including the verification_method enum is documented in the schema. The description's mention of "DNS/HTTP instructions" hints at what verification_method controls but adds no format or default detail beyond the structured fields, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Start a B2B domain verification") and adds the concrete side effect: creates a verification record and returns DNS/HTTP instructions. That is a clear purpose, but with siblings like start_domain_email_verification, start_user_domain_verification, and verify_domain, the description never explicitly says how it differs beyond the loose "B2B" qualifier.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a real precondition (needs a Proof account, set PROOF_API_KEY and restart the server) and usefully rules out one path ("start_login does NOT open this tool"). However, it offers no when-to-use routing against the many overlapping verification tools, so an agent must still guess between this and create_verification or start_user_domain_verification.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_loginAInspect
Start a login session by sending an authentication challenge to the user's chosen channel (Telegram, WhatsApp, SMS, or email). Returns a session ID and, FOR TELEGRAM AND WHATSAPP ONLY, deep_link, qr_code (base64 PNG) and qr_text (UTF-8 text QR for terminal display); on sms it returns sms_message with sms_dids instead, and on email nothing to display.
Agent usage: (1) Call start_login with the desired channel and phone_number (for SMS) or email (for email). (2) Present the challenge, and WHICH FIELD depends on the channel. On telegram/whatsapp pass deep_link to render_auth_link, which returns the clickable link and a QR code to you; in a chat client the link is what the user acts on, since they are usually on the same machine. On sms deep_link is an EMPTY STRING and render_auth_link will reject it — show sms_message and let the user pick a number from sms_dids. suggested_region is always set, but the matching ENTRY in sms_dids may be missing (europe and israel appear only when a number is configured) or present with an empty did, so offer that region first only when sms_dids[suggested_region] exists and carries a number, and otherwise offer whatever the object does. On email there is nothing to display at all, and nothing to check either: a result means the mail was accepted for delivery, so tell the user to open their inbox. A delivery failure is an ERROR here, not a field — the tool answers challenge_delivery_failed and NO session exists, so do not call wait_for_login; retry, or offer another channel. Never hand qr_text to a link renderer — it is the link already rendered as QR art, so print it verbatim inside a fenced code block or not at all, because its rows stop scanning the moment one wraps or a blank line lands between them. (3) Once your reply shows the user the challenge, call wait_for_login with the returned session ID to poll until the user completes authentication. On email, tell the user to open the link and press "Sign in the browser that requested this": the page also offers "Sign in here", which signs in the browser they clicked from instead of this connection. Terminal states: "verified" (login succeeded), "failed", "expired", "completed_elsewhere" (email only: the user pressed "Sign in here" on the email link's page, so the browser they clicked from is signed in and this connection never will be — tell them so, and start a new login if this connection still needs one).
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
| Name | Required | Description | Default |
|---|---|---|---|
| No | Email address (required for email channel) | ||
| channel | Yes | Authentication channel | |
| phone_number | No | Phone number in E.164 format (required for SMS channel) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| type | No | |
| status | No | Status of an auth session. `completed_elsewhere` (terminal, no cookies): an email sign-in the person completed in ANOTHER browser by pressing "Sign in here" on the link's page — this session will never become `verified`. |
| channel | No | Authentication channel |
| qr_code | No | Base64-encoded QR code image |
| qr_text | No | UTF-8 text representation of the QR code for terminal/agent display |
| user_id | No | |
| deep_link | No | |
| expires_at | No | |
| verified_at | No | |
| instructions | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false, yet the description discloses far more: delivery failure surfaces as an error with no session created, the four terminal states including the email-only completed_elsewhere trap, and the constraint that the user never sees tool output. That is real behavioral context beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and return payload, then organized into numbered steps with per-channel branches. It is long for a three-parameter tool and repeats the 'which field to show depends on channel' point more than once, with heavy all-caps emphasis, but nearly every sentence carries an actionable instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full lifecycle an agent needs: inputs, per-channel returns, the render_auth_link handoff, the polling step, error behavior, and terminal states. Even though an output schema exists, the description adds the sequencing and user-facing presentation rules the schema cannot express.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3; the description nonetheless ties each parameter to a channel outcome (phone_number for SMS, email for email) and frames channel choice as determining the entire response shape. It stops short of adding format detail beyond the schema's E.164 and email pattern notes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb and resource: 'Start a login session by sending an authentication challenge' across four named channels, plus the return payload per channel. It clearly separates itself from wait_for_login, render_auth_link and the start_2fa / start_add_* siblings by being the entry point of a login (not a 2FA or contact-add) flow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit numbered procedure, names the alternative tools at each step (render_auth_link, wait_for_login), and states when NOT to use them (sms deep_link is empty and render_auth_link will reject it; do not call wait_for_login after challenge_delivery_failed). Channel-by-channel branches leave almost nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_user_domain_verificationAInspect
Start a self-service domain verification session. The user proves ownership of a domain via DNS or HTTP challenge.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name to verify (e.g. example.com) | |
| channel | No | Verification channel (default: dns) |
Output Schema
| Name | Required | Description |
|---|---|---|
| domain | Yes | |
| status | Yes | |
| channel | Yes | |
| challenge | Yes | What to publish: a TXT record (`dns`) or a file on the site (`http`) |
| expires_at | Yes | |
| session_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description goes further by disclosing the hard access prerequisite (Proof account, PROOF_API_KEY, restart or sign-in) and that this tool opens a session. That is genuine context an agent cannot get from the structured fields, though it does not say how long the session lives or what happens if one is already open.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks: purpose first, then a clearly labeled ACCESS note. No wasted wording, and the most important fact (what the tool does) is front-loaded. The access sentence is slightly dense but earns its place as a prerequisite.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be explained, and the access prerequisite is covered. But for a flow-opening tool in a crowded verification family, the description omits what the caller does next and how this differs from the other start_*_verification siblings, leaving a meaningful gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters (domain example, channel enum with dns/http) are already documented in the schema. The description's mention of 'DNS or HTTP challenge' mirrors the enum without adding format, defaults, or constraints beyond it, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb and resource ('Start a self-service domain verification session') and adds the mechanism (DNS or HTTP challenge), which is more than a restatement of the name. However, it never distinguishes itself from close siblings like start_domain_verification or start_domain_email_verification, so an agent must infer whether 'self-service' is the sole differentiator.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'the user proves ownership of a domain via DNS or HTTP challenge', and the colleague names start_login as an alternative path for obtaining access. But there is no explicit when-not guidance and no routing to the sibling that should be called after this one (check_user_domain_verification / get_user_domain_verification_status).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_verification_codeAInspect
Submit an OTP/challenge code for a pending verification. Accepted ONLY where we delivered the code out-of-band to the party being verified: type "email", and type "domain" with channel "email". Any other pair answers 400 unsupported_for_type and completes elsewhere — use trigger_verification (POST /verifications/:id/verify) for a domain over dns/http/auto; a phone completes when the code reaches us FROM that number; social completes through its OAuth callback; a telegram_bot is already verified at creation.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification ID | |
| code | Yes | The OTP or challenge code to submit |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| proof | No | Present when the code was right |
| status | Yes | Current status of the verification |
| message | No | Present when the code was wrong (`pending`) or the attempts are used up (`failed`) |
| attempts | Yes | Codes submitted so far, this one included |
| verified_at | No | Present when the code was right |
| max_attempts | Yes | |
| attempts_remaining | No | Present while `pending` |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description adds real behavioral context beyond that: the 400 unsupported_for_type failure mode for unsupported pairs and the exact access precondition (Proof account, PROOF_API_KEY set plus server restart). It also preempts a plausible wrong assumption by noting start_login does NOT unlock this tool. Nothing contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The eligibility constraint is front-loaded, then the routing table for excluded cases, then the access note — a sensible order with dense, non-repeating sentences. It is long for a two-parameter tool, but nearly every clause conveys a distinct constraint; the ACCESS paragraph is useful though slightly tangential to invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description covers the remaining gaps an agent would hit: auth setup, unsupported-input behavior, and the alternative path for every excluded verification type. Complete for this tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both required parameters (id, code), so the schema carries parameter meaning and the baseline of 3 applies. The description's discussion of 'type' and 'channel' pairs is routing context rather than semantics for id or code, so it adds little parameter-level detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Submit an OTP/challenge code for a pending verification.' It immediately constrains the scope to conditions where the code was delivered out-of-band, which separates it from the many other verification tools, and names trigger_verification as the different sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('ONLY where we delivered the code out-of-band... type "email", and type "domain" with channel "email"') and when-not, enumerating each excluded case with the mechanism that handles it instead (trigger_verification for dns/http/auto, inbound phone submission, social OAuth callback, telegram_bot already verified). No inference is left to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
test_verifyAInspect
Auto-complete a verification in test mode (pk_test_* API keys only). Useful for testing flows without real OTP delivery.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| type | Yes | Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account. |
| status | Yes | |
| channel | Yes | Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken. |
| test_mode | Yes | |
| identifier | Yes | |
| proof_token | Yes | |
| verified_at | Yes | |
| proof_expires_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and destructiveHint=false, so the state-mutating nature is already signalled and the description does not contradict it. The description adds genuinely useful context beyond the annotations: the test-key requirement, the need for PROOF_API_KEY, and the server-restart step. It stops short of describing what a live-key call does or what failure looks like.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the mode constraint and purpose front-loaded, then a clearly labelled ACCESS block. Nothing is padded, though the 'then call this tool again' phrasing is slightly awkward as a standing definition for an agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, output-schema-backed tool with annotations present, the definition covers the operational essentials: test-key scope, auth setup, and a known false lead (start_login). Return values need not be explained given the output schema, leaving little material missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is only one parameter and schema coverage is 100%, so the schema already documents 'id' as a Verification ID. The description adds no extra meaning about where that ID comes from (create_verification, trigger_verification) or how it is formatted, so the baseline applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Auto-complete a verification') and scopes it to test mode with pk_test_* keys. That mode constraint is what separates it from adjacent verification tools such as trigger_verification or submit_verification_code, though none of those siblings are named directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear use case ('testing flows without real OTP delivery') and the hard precondition of pk_test_* keys. It also pre-empts a plausible wrong turn by stating 'start_login does NOT open this tool', which is real alternative guidance, but it never tells the agent when to prefer a non-test sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
trigger_verificationAInspect
Trigger a DNS/HTTP verification check for a pending domain verification.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| type | No | Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account. |
| proof | No | Proof token after successful verification |
| status | No | Current status of the verification |
| channel | No | Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken. |
| attempts | No | |
| challenge | No | Challenge details for verification |
| created_at | No | |
| identifier | No | The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it |
| updated_at | No | |
| verified_at | No | |
| max_attempts | No | |
| external_user_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations say non-read-only and non-destructive but give no auth or lifecycle context; the description fills that gap by disclosing the account/API-key requirement, the restart step, and the non-obvious fact that start_login will not grant access. It does not say whether the triggered check is asynchronous, whether it can be re-triggered, or if it is rate-limited — but relative to the annotation baseline this adds substantive behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight blocks: the action first, then a clearly labeled ACCESS constraint. No filler sentences, and the operational blocker is surfaced prominently rather than buried. Slightly heavy on the auth preamble relative to one line of purpose, but every sentence is actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the description need not explain return values, and the auth gate is well covered. What is missing for a complex verification workflow is the follow-up path — e.g. that the agent should poll check_domain_verification or wait_for_verification afterward — leaving the agent unsure what to do once the check is triggered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter with 100% schema description coverage ('Verification ID'), so the schema already carries the semantics. The description confirms the tool operates on a pending domain verification but adds no extra detail on where that ID comes from or what state the verification must be in.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a concrete verb and resource — 'Trigger a DNS/HTTP verification check for a pending domain verification' — so the agent knows it kicks off a network check on an existing verification. It stops short of distinguishing this from near-identical siblings such as check_domain_verification, start_domain_verification, or verify_domain, which is the main clarity gap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It supplies a real precondition (a Proof account with PROOF_API_KEY set, plus a server restart) and explicitly rules out start_login as a way to unlock it, which is useful when-to-use guidance. However, it never says when to prefer this over check_domain_verification or start_domain_verification, so sibling selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_circleADestructiveInspect
Update a Circle's name and/or owner name. Omitted fields are left unchanged; the profile/identity binding is create-only.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Circle ID | |
| name | No | New name for the Circle | |
| owner_name | No | How this Circle's members know its owner ("Dad", "Giorgi"). The bots name the owner by it; while it is empty they name nobody — the Circle's name labels the group, never the person. Trimmed by the API; null or an empty value clears it. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| name | No | |
| status | No | Lifecycle state of a Circle (archived = soft-retired) |
| members | No | |
| user_id | No | |
| created_at | No | |
| owner_name | No | How this Circle's members know its owner; null when unset |
| profile_id | No | |
| updated_at | No | |
| environment | No | |
| member_count | No | |
| proof_me_enabled | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, and the description adds meaningful context beyond them: partial-update merge semantics, the create-only constraint on identity binding, and a concrete auth prerequisite (PROOF_API_KEY plus server restart, and that start_login does not unlock this tool). It does not explain why the update is flagged destructive or whether a name change is reversible, leaving a small gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and partial-update rule are front-loaded in the first sentence, with the create-only caveat immediately after. The ACCESS block is separated and actionable rather than buried. Slightly verbose in the auth explanation, but every sentence carries operational value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a fully described schema and an output schema present, the description covers what remains: mutation scope, partial-update behavior, and the account prerequisite. It omits any mention of failure modes (e.g., invalid ID format, permission errors) or effects on existing members, which is a minor but real gap for a destructive-flagged mutation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the owner_name field already carries a rich explanation in the schema (including null-clearing and trimming behavior). The description adds only the aggregate rule that omitted fields are unchanged, which is useful but does not deepen any individual parameter's meaning. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Update a Circle's name and/or owner name') and names the exact mutable fields, so it is clearly distinguishable from create_circle, get_circle and delete_circle. It stops short of naming those siblings explicitly, so it is clear but not maximally differentiating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a real usage rule: 'Omitted fields are left unchanged', which tells an agent that partial updates are safe and that absent fields need not be supplied. It also states that the profile/identity binding is create-only, steering the agent away from a use this tool cannot serve. No explicit alternative-tool routing is given, but the mutation scope is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_hitlBDestructiveInspect
Update a HITL config. Can change name, channels, or timeout.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | HITL config ID | |
| name | No | New name (null to clear) | |
| channels | No | Updated channels | |
| timeout_seconds | No | Updated timeout in seconds (60–86400) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| name | No | |
| status | Yes | Status of a HITL configuration |
| keypair | Yes | Encryption keypair metadata (null if not configured) |
| user_id | Yes | Owner user ID (useful for SDK encryption AAD) |
| channels | Yes | |
| circle_id | No | Backing Circle for a circle-backed Approvals config (null for channel-list configs) |
| created_at | Yes | |
| profile_id | No | |
| updated_at | Yes | |
| environment | Yes | |
| timeout_seconds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, and the description adds genuinely useful non-schema context about the API-key prerequisite. However, it never explains what the destructive aspect is — notably whether passing 'channels' replaces the entire channel list or merges with it, and whether omitted fields are left untouched. For a mutation tool flagged destructive, that omission is a real gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, front-loaded with the core action before the access caveat, with no filler sentences. The ACCESS paragraph is operational rather than descriptive, but it earns its place by preventing a likely failed call.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and all four parameters are documented in the schema. What remains missing is the mutation's effect model — replace vs merge for channels, and confirmation of whether this is a partial update — which matters given the destructiveHint.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: 'id', null-to-clear on 'name', channel shapes, and the 60–86400 timeout range are all documented in the schema. The description only restates the field list, adding no patch-vs-replace semantics or interpretation of null/omitted values beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Update a HITL config') and enumerates the mutable fields (name, channels, timeout), which distinguishes it from create_hitl/get_hitl/delete_hitl among the siblings. It stops short of explicitly naming those siblings as alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The tool is implied to operate on an existing config identified by 'id', and the ACCESS block tells the agent a Proof account plus PROOF_API_KEY is required and that start_login does not unlock this tool. That is authentication guidance, not when-to-use guidance: there is no statement of exclusions or pointers to create_hitl/get_hitl for adjacent tasks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_my_profileBDestructiveInspect
Update the current user's primary profile. Supports display name, bio, avatar, theme, custom links, and verification display settings.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| bio | No | Profile bio | |
| theme | No | Profile theme settings | |
| is_public | No | Whether the profile is publicly visible | |
| avatar_url | No | Avatar (HTTPS URL or base64 data URI, null to remove) | |
| custom_links | No | Custom links (max 20) | |
| display_name | No | Display name | |
| show_delegations | No | List the published, in-force delegations for the domains the profile shows (default true) | |
| show_proof_channels | No | Show proof channels | |
| show_verification_dates | No | Show verification dates |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bio | No | |
| theme | Yes | Profile theme customization |
| username | No | Absent until a username is claimed |
| is_public | Yes | |
| avatar_url | No | A URL or a data URI; null once cleared |
| created_at | Yes | |
| is_primary | Yes | |
| profile_id | Yes | The public id used in profile URLs |
| updated_at | Yes | |
| view_count | Yes | |
| email_theme | Yes | Theme of this sub-account's emails; null when unset (read as `dark`). |
| is_business | Yes | |
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| custom_links | Yes | |
| display_name | No | |
| business_name | No | |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
| support_email | Yes | Support address shown in this sub-account's messages; null when unset. |
| show_delegations | Yes | |
| verification_level | Yes | Always 'basic'; no levels are computed; removed in the next major. |
| show_proof_channels | Yes | |
| show_verification_dates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, and the description adds useful operational context the annotations cannot carry: the account requirement and the API-key setup step. It does not, however, explain the destructive behavior the annotation warns about — whether omitted fields are cleared, whether links/theme are replaced wholesale, or whether changes are reversible — which is the key unknown for a destructive mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs, purpose front-loaded, with the blocking prerequisite separated out and stated tersely. Nothing is padded, though the access note could be tightened by giving the env-var requirement in one clause rather than a retry instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be described, and the account prerequisite is covered. What remains missing for a nine-parameter destructive mutation with nested objects is partial-update semantics and the effect on fields not supplied — information an agent needs to call this safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all nine parameters including nested theme and custom_links fields. The description's field list (display name, bio, avatar, theme, custom links, verification display settings) mirrors the schema rather than adding constraints or semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Update the current user's primary profile" gives a specific verb and a scoped resource, and "primary" implicitly separates it from the sibling update_profile. However, it never names update_profile, set_primary_profile, or get_my_profile, so the agent must infer the distinction from a single adjective.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The access paragraph gives a real prerequisite (Proof account + PROOF_API_KEY) and an explicit exclusion (start_login does not open this tool). But there is no guidance on when to choose this over update_profile, set_primary_profile, or update_profile_proofs, which is the main selection ambiguity among siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_profileBDestructiveInspect
Update a profile by ID. Supports changing display info, email branding (theme, support email), theme, custom links, and verification display settings.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| bio | No | Profile bio | |
| theme | No | Profile theme settings | |
| is_public | No | Whether the profile is publicly visible | |
| avatar_url | No | Avatar (base64 or URL, null to remove) | |
| is_primary | No | Set as primary profile | |
| profile_id | Yes | Profile ID | |
| email_theme | No | Theme of this sub-account's emails | |
| is_business | No | Whether this is a business profile | |
| custom_links | No | Custom links (max 20) | |
| display_name | No | Display name | |
| business_name | No | Business name | |
| support_email | No | Support email this sub-account's messages show (null to remove) | |
| show_delegations | No | List the published, in-force delegations for the domains the profile shows (default true) | |
| show_proof_channels | No | Show proof channels on public profile | |
| show_verification_dates | No | Show verification dates on public profile |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| bio | No | |
| theme | Yes | Profile theme customization |
| username | No | Absent until a username is claimed |
| is_public | Yes | |
| avatar_url | No | A URL or a data URI; null once cleared |
| created_at | Yes | |
| is_primary | Yes | |
| profile_id | Yes | The public id used in profile URLs |
| updated_at | Yes | |
| view_count | Yes | |
| email_theme | Yes | Theme of this sub-account's emails; null when unset (read as `dark`). |
| is_business | Yes | |
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| custom_links | Yes | |
| display_name | No | |
| business_name | No | |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
| support_email | Yes | Support address shown in this sub-account's messages; null when unset. |
| show_delegations | Yes | |
| verification_level | Yes | Always 'basic'; no levels are computed; removed in the next major. |
| show_proof_channels | Yes | |
| show_verification_dates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag this as a non-read-only, destructive mutation, and the description usefully adds the account/auth setup requirement that annotations cannot convey. However, for a destructive update it never explains update semantics an agent needs: whether omitted fields are preserved, whether custom_links replaces the entire list, or what removing avatar_url/support_email with null does. That gap matters given destructiveHint=true.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight paragraphs: purpose first, prerequisite second, both front-loaded. The access note is slightly verbose ('restart this server, then call this tool again') but it carries non-obvious information, so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values need no explanation, and the 15-param surface is fully documented in the schema. What's missing is proportionate to the risk: this is a destructive mutation with nested objects and list-replacement semantics, yet the description says nothing about partial-update behavior or overwrite scope.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every one of the 15 parameters is already documented in the schema, including enum values, hex patterns, and the max-20 custom links constraint. The description only groups fields into functional categories (email branding, theme, links, verification display), adding light orientation but no syntax or semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Update') and resource ('a profile by ID') and enumerates the categories of changeable fields: display info, email branding, theme, custom links, verification display settings. It doesn't explicitly distinguish itself from close siblings such as update_my_profile or update_profile_proofs, so an agent must infer that 'by ID' means an arbitrary profile rather than the caller's own.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only guidance is an access prerequisite (PROOF_API_KEY, restart, start_login won't unlock it), which is about authentication, not tool selection. There is no statement of when to use this versus update_my_profile, set_primary_profile, or update_profile_proofs, and no indication of which field groups require which flags.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_profile_proofsBDestructiveInspect
Update which verified assets (proofs) are displayed on a specific profile. Controls visibility, privacy masking, ordering, and labels.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| proofs | Yes | Proofs to display on profile | |
| profile_id | Yes | Profile ID | |
| proof_order | No | Who orders the shown proofs: `default` (domain, social, Telegram bot, email, phone, wallet, then display_order) or `owner` (display_order alone). Omitted, the profile keeps its current setting. |
Output Schema
| Name | Required | Description |
|---|---|---|
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so the safety profile is known. The description adds real value with the account/restart prerequisite, but it never explains the destructive mechanics: whether the proofs array replaces the entire existing set, what happens to proofs omitted from it, or whether visibility changes are reversible. For a flagged-destructive mutation that is a meaningful omission.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight blocks: purpose first, then a clearly separated ACCESS note, both front-loaded with no filler. The access block is longer than the functional description, which is slightly disproportionate but justified by the hard prerequisite.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists and annotations carry the safety profile, so the description need not explain returns. What is missing is the replacement semantics of the proofs array and any disambiguation from update_public_proofs, both of which matter for a destructive, profile-scoped write.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with every property including the proof_order enum fully documented in the schema. The description's closing sentence ('visibility, privacy masking, ordering, and labels') merely restates those fields rather than adding format or ordering semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Update which verified assets (proofs) are displayed on a specific profile') and enumerates the aspects it controls. It does not differentiate itself from the very similar sibling update_public_proofs, which an agent will likely confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a strong precondition (a Proof account with PROOF_API_KEY set) and explicitly rules out start_login as a path to enabling the tool, which is genuinely useful routing information. However, it offers no guidance on when to choose this over update_public_proofs or update_profile, leaving the sibling-selection problem unresolved.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_public_proofsADestructiveInspect
Update which verified proofs are visible on the user's public profile, including visibility, masking, and display order.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| proofs | Yes | Array of proof display configurations (max 50) | |
| proof_order | No | Who orders the shown proofs: `default` (domain, social, Telegram bot, email, phone, wallet, then display_order) or `owner` (display_order alone). Omitted, the profile keeps its current setting. |
Output Schema
| Name | Required | Description |
|---|---|---|
| proof_order | Yes | Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting. |
| public_proofs | Yes | The shown proofs, in the order the public profile shows them |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as a non-read-only, destructive operation. The description adds useful access requirements and lists the affected proof attributes, but it does not explain whether the supplied proofs array replaces all existing public proofs or what happens to omitted proofs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the purpose and followed by a compact access note. Both sentences earn their place and there is no unnecessary wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema exists, annotations disclose destructiveness, and authentication is covered. Still, for a destructive public-profile mutation, the missing explanation of replacement behavior and the overlap with update_profile_proofs leaves a meaningful gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter and nested field. The description adds only high-level context about visibility, masking, and display order, without clarifying proof_order or replacement semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: updating which verified proofs are visible on the user's public profile, including visibility, masking, and display order. It is clear what the tool does, but it does not distinguish it from the very similarly named sibling update_profile_proofs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the public-profile proof configuration context, and the access prerequisite is explained. However, there is no explicit guidance on when to use this instead of update_profile_proofs or other profile-related siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_settingsADestructiveInspect
Update account settings: the outbound webhook endpoint with its event subscriptions, and the default proof lifetime. Branding belongs to each sub-account: change it with update_profile. Setting the first webhook endpoint creates the signing secret and returns it in this response; the value is returned only when this call created or rotated it, so record it then.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| hitl | No | Approval-setup settings | |
| webhook | No | Outbound webhook configuration. Deliveries carry an HMAC-SHA256 X-Proof-Signature over "<X-Proof-Timestamp>.<body>". | |
| proof_expiry_days | No | Default proof-token lifetime in days for newly issued proofs |
Output Schema
| Name | Required | Description |
|---|---|---|
| hitl | No | Approval-setup settings. |
| success | No | |
| webhook | No | Outbound webhook configuration — DEPRECATED (#421). An account switched over to webhook endpoints sees its account-wide (`legacy`) endpoint here: `url` is null while that endpoint is disabled, a `url` write updates or creates it, `url: null` disables it (its secret is kept), and `rotate_secret` rotates its secret. An account not yet switched over sees its settings fields, as before. Omitted for an API key bound to one sub-account. |
| proof_expiry_days | No | Default lifetime in days of newly issued verification proofs, or null when the account has never set one. Confirmation-decision proofs do not use it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, it discloses the key side effects an agent cannot infer: setting the first endpoint mints a signing secret, the secret is returned only on creation or rotation so it must be recorded immediately, and rotating kills the old value for verification instantly. It also states the auth precondition and that start_login does not unlock this tool, which is exactly the kind of info that prevents a failed call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight paragraphs: the scope and the update_profile split come first, the irreversible secret behavior next, and the access prerequisite is isolated in a clearly labeled block. Every sentence earns its place; the only cost is that the dense secret-handling sentence packs creation and rotation semantics into one clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations, a full output schema and 100% schema coverage, the description supplies the pieces structured data cannot: access prerequisites, secret lifecycle, and the branding-to-profile routing. The remaining gaps are the unmentioned `hitl` group and the lack of routing against the dedicated webhook-endpoint and secret-rotation tools that overlap this one.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already carries most parameter meaning and the baseline is 3. The description does add value for the webhook URL (that providing one creates the signing secret) and for the returned secret, but says nothing about the `hitl.approver_password_min_length` setting even though it is one of the three top-level parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Update account settings" is paired with a concrete enumeration of the mutable resources (outbound webhook endpoint with event subscriptions, default proof lifetime), which makes the scope unambiguous. It also explicitly separates branding from this tool and points at update_profile. The enumeration is incomplete, though: the `hitl` approval-password setting is a top-level parameter that the opening sentence never mentions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear when-not ("Branding belongs to each sub-account: change it with update_profile") and a concrete precondition sequence for access (set PROOF_API_KEY, restart, retry; start_login will not help). What it omits is the more pressing ambiguity: the sibling set contains create_webhook_endpoint, update_webhook_endpoint and rotate_webhook_endpoint_secret, and the description never says when to use this settings-level webhook block instead of those dedicated tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_templateADestructiveInspect
Create or update a sub-account's custom template for a channel and message type, replacing the default for that sub-account only. Name the brand with {{business_name}}: a template spelling out a sub-account's own name is refused (template_hardcoded_name). A template for a channel and message type no message is sent for, or using a variable that message never fills, is still saved, with an entry in warnings (template_not_sent / template_variable_not_filled) saying why it will not be sent as written (an API that predates warnings omits the field).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Template body text with variable placeholders | |
| channel | Yes | Message channel | |
| subject | No | Email subject line (email channel only) | |
| profile_id | No | The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key | |
| button_text | No | Button text (email channel only) | |
| message_type | Yes | Message type (e.g. verification_request, login_request) | |
| button_url_template | No | Button URL template with placeholders |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | No | |
| template | No | Message template |
| warnings | No | Why this template would never be sent as written; empty when it would be. Always sent; absent from an API that predates it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint=true annotation, it discloses the overwrite effect on the sub-account default, the hard refusal rule with its error code (template_hardcoded_name), and the non-obvious save-with-warnings behavior with both warning codes (template_not_sent / template_variable_not_filled) plus the older-API caveat that `warnings` may be absent. These are exactly the behaviors an agent cannot infer from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the action and scope before the rules and the access block. The access paragraph is boilerplate but necessary for a tool gated behind an API key, and no sentence is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter mutation with an output schema, it covers the action, overwrite semantics, failure and warning modes, and auth requirements. Only minor gaps remain: whether subject/button fields are rejected or ignored on non-email channels, and what the response contains on a successful create versus update.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning for the placeholder-bearing fields: the {{business_name}} variable is required for branding and a hardcoded sub-account name is refused, and variables must be ones the message type actually fills. It says nothing extra about profile_id resolution beyond the schema, so it stops short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb pair (create or update), the exact resource (a sub-account's custom template), and the scoping keys (channel and message type), plus the qualifier 'replacing the default for that sub-account only'. That distinguishes it from list_templates, get_template, preview_template, render_template and delete_template without naming them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the access precondition explicitly (needs a Proof account, set PROOF_API_KEY, restart the server) and pre-empts a wrong path by noting 'start_login does NOT open this tool', which is real when-not guidance. What's missing is routing to the read-side siblings, e.g. preview_template to check a body before saving or get_template to read the current one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_webhook_endpointADestructiveInspect
Update a webhook endpoint: its URL, events, scope, sub-accounts, status or description. Every field is optional, but send at least one. Changing the scope to "selected" without profile_ids keeps the stored list. The signing secret is unchanged (rotate it with rotate_webhook_endpoint_secret).
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Webhook endpoint ID | |
| url | No | HTTPS URL deliveries are sent to, at most 2000 characters. Private, loopback and link-local addresses are refused. | |
| scope | No | "all" serves every sub-account, present and future, plus account-level events; "selected" serves only the sub-accounts in profile_ids | |
| events | No | Subscription patterns (at most 32): an exact event type, a family wildcard such as "proof.*", or "*". An empty list means every event. | |
| status | No | A disabled endpoint receives nothing | |
| description | No | Your own label for the endpoint, at most 200 characters; null clears it | |
| profile_ids | No | Sub-account ids, 24 hex characters each, at most 100. At least one when scope is "selected"; none when scope is "all". |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| url | No | HTTPS URL deliveries are POSTed to, at most 2000 characters. Private, loopback and link-local addresses are refused. |
| scope | No | `all` — every sub-account, present and future, plus account-level events. `selected` — only the sub-accounts in `profile_ids`; account-level events never reach it. |
| events | No | |
| legacy | No | The endpoint converted from the account's single webhook URL — the one the deprecated `/me/settings` webhook block reads and writes. |
| status | No | A `disabled` endpoint receives nothing; its history and secret are kept. |
| created_at | No | |
| secret_set | No | Whether the endpoint has a signing secret (always true). |
| updated_at | No | |
| description | No | |
| profile_ids | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, yet the description still adds real behavioral context: partial updates leave unset fields intact, the stored profile list survive an omitted profile_ids when scope is "selected", and the signing secret is untouched by an update. It doesn't explain why the operation is marked destructive (e.g. what a scope change to "all" discards), which is the one gap given that annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The mutable fields and the at-least-one constraint are front-loaded, followed by the two non-obvious edge cases, then a discrete ACCESS block. Every sentence is load-bearing, including the explicit warning that start_login will not unlock this tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and annotations cover the safety profile. Given 7 parameters and a destructive update, the description supplies the missing pieces: optionality, inter-field behavior, the secret boundary, and the auth prerequisite.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description earns above that by documenting cross-parameter behavior the schema cannot express: the scope/profile_ids coupling and the at-least-one-field rule. It doesn't add format detail for individual fields, but the schema already carries that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb plus resource ("Update a webhook endpoint") and enumerates the mutable surface: URL, events, scope, sub-accounts, status, description. An agent can immediately tell this apart from rotate_webhook_endpoint_secret or create_webhook_endpoint without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear operating condition ("Every field is optional, but send at least one") and routes secret rotation to the named sibling rotate_webhook_endpoint_secret. It also states the access prerequisite. It stops short of saying when to prefer this over, say, delete_webhook_endpoint or when an update is inappropriate, but the practical guidance is well above average.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_hitl_keysADestructiveInspect
Upload an encryption keypair for a HITL config. The server validates the RSA-4096 public key and computes the key ID. Note: the encrypted_private_key is already encrypted client-side with the user's password — the server never sees the password.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| dek_iv | No | v2 envelope: the IV of that wrapping | |
| dek_tag | No | v2 envelope: the GCM tag of that wrapping | |
| hitl_id | Yes | HITL config ID | |
| kdf_salt | Yes | Base64url-encoded PBKDF2 salt | |
| public_key | Yes | PEM-encoded RSA-4096 SPKI public key | |
| wrapped_dek | No | v2 envelope: the data key wrapped under the master key | |
| backup_dek_iv | No | v2 envelope: the IV of the recovery wrapping | |
| backup_dek_tag | No | v2 envelope: the GCM tag of the recovery wrapping | |
| backup_wrapped_dek | No | v2 envelope: the data key wrapped under the recovery code | |
| encrypted_private_key | Yes | JSON-serialized encrypted private key envelope (PBKDF2-SHA256+AES-256-GCM) |
Output Schema
| Name | Required | Description |
|---|---|---|
| kid | Yes | The stored key's id |
| message | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, and the description adds genuinely useful behavior the annotations cannot convey: server-side validation, server-computed key ID, and that the password never leaves the client. However, it never addresses the destructive half of the profile - what happens to a previously uploaded keypair, whether re-upload replaces or errors, and whether the old key becomes undecryptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and followed by the validation note and the access caveat, with no filler. The encryption caveat and the access block are separated cleanly enough that an agent can stop reading after the first sentence if it already has credentials.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no prose, and the auth blocker is covered well. Against a 10-parameter cryptographic tool with a destructive annotation, though, the description leaves the overwrite/replacement semantics and the meaning of the six optional v2 envelope parameters entirely to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already labels every field. The description still adds real meaning for two of them - public_key must be RSA-4096 and encrypted_private_key is client-side PBKDF2/AES-256-GCM output, with the password never transmitted - which is beyond the schema. It says nothing about the optional v2 envelope fields (wrapped_dek, dek_iv, dek_tag, backup_*), so the gain over the schema is partial.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Upload an encryption keypair for a HITL config") and adds that the server validates the RSA-4096 public key and derives the key ID, which tells the agent this is not a blind write. It does not name the adjacent siblings get_hitl_keys / delete_hitl_keys, so the distinction is inferable from the name rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS block gives concrete preconditions (Proof account, PROOF_API_KEY set, server restart) and explicitly rules out a tempting wrong path with "start_login does NOT open this tool." What is missing is any guidance on when to re-upload versus read existing keys with get_hitl_keys, or whether a HITL config must already exist.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_proofARead-onlyInspect
Validate a proof token online. Checks the token signature, expiry, and revocation status against the server, and optionally that the proof is about the identifier you expect. Public endpoint — no API key required.
| Name | Required | Description | Default |
|---|---|---|---|
| identifier | No | Optional: the identifier this proof should be about (phone, email, domain, ...). When supplied, a proof about anything else answers valid:false with reason "identifier_mismatch"; a proof of an encrypted decision answers "identifier_unverifiable". | |
| proof_token | Yes | The JWT proof token to validate |
Output Schema
| Name | Required | Description |
|---|---|---|
| valid | Yes | |
| reason | No | Failure reason: expired, revoked, suspended (a reversible pause — the owner can lift it), invalid (for a token signed by a current registry key this includes a token the issuer has no record of issuing), superseded (the proof was verified again and this token was replaced by a newer one for the same proof — use the newer token; offline verification does not see this), key_revoked (the token names a signing key the issuer has revoked; decided from its `kid` before the signature is checked, so it does not vouch for the token — a genuine holder fetches a re-signed one), identifier_mismatch (the supplied identifier is not what this proof is about), or identifier_unverifiable (the proof's hash is derived from ciphertext, so no identifier can be bound to it) |
| message | No | Human-readable message |
| proof_id | No | Public proof id (ph_ctl_*), present when the proof is registered |
| delegation | No | Delegation claim set, present when a valid delegation token was submitted. The attestation is domain authorization of the artifact — NOT that the artifact is safe, audited or endorsed. |
| revoked_at | No | When the proof was revoked (only present when reason is "revoked") |
| token_type | No | Present ONLY when the submitted token is a delegation (m-delegation-verifier-ref). Its absence means the answer is about a verification/decision proof and the `verification` block applies. |
| suspended_at | No | When the suspension began — present only with reason `suspended` |
| verification | No | |
| revoked_reason | No | Reason for revocation (only present when reason is "revoked") |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnlyHint, so the description adds real context: it performs a server round-trip rather than a local parse, the checks include revocation status, and it needs no API key. The revocation lookup in particular is behavior an agent could not infer from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action and followed by the specific checks, closing with the auth requirement. No filler and nothing important buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, and both parameters are fully documented in the schema. The description covers purpose, the checks performed, and the public-endpoint requirement; only explicit sibling routing is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the identifier property already documents the identifier_mismatch and identifier_unverifiable outcomes far more precisely than the description. The description's restatement of "optionally that the proof is about the identifier you expect" adds nothing beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Validate a proof token online" gives a specific verb and resource, and the follow-up sentence enumerates what is actually checked (signature, expiry, revocation). It is clear enough to call correctly, but it never explicitly contrasts itself with adjacent siblings such as get_proof_status or get_proof_token.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The "online" / "against the server" framing implies this is the live-check path versus stored proof lookups, and the optional identifier check is described. However, there is no explicit when-to-use or when-not-to-use guidance naming the alternatives (get_proof_status, list_revoked_proofs), so the agent must infer routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_2faAInspect
Submit a verification code to complete a 2FA challenge. Rate limited to 10 attempts per minute.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Verification code | |
| session_id | Yes | 2FA session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | |
| verified_at | Yes | |
| grant_expires_at | Yes | When the grant this step-up stored stops being accepted |
| grant_single_use | Yes | Whether the grant is spent by the first act it allows |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false, so the rate limit of 10 attempts per minute and the authentication/session prerequisite are genuinely additive information the agent could not get elsewhere. It does not say what a failed or expired code returns, which would round out the picture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and the rate limit are front-loaded in one tight sentence, with prerequisites separated into a labeled ACCESS block. The ACCESS text is somewhat boilerplate about server configuration, but it is clearly demarcated and not woven into the action description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description covers the two things an agent most needs: the rate limit and the auth/session requirement. Only failure behavior and code expiry are left unstated for a two-parameter flow-completion tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both required parameters, so the schema already carries the load. The description mentions "verification code" and the session context but adds no format, length, or expiry semantics beyond what the schema states. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Submit a verification code to complete a 2FA challenge" names a concrete action and resource, and the phrase "complete a 2FA challenge" signals this is the finishing step of a flow. It does not, however, distinguish itself from close siblings such as verify_2fa_magic_link or submit_verification_code, so an agent must infer which verification path applies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS paragraph gives real preconditions: a Proof account, PROOF_API_KEY set, or a session opened by start_login. That tells the agent when the call will succeed. It stops short of explicitly ruling out alternatives like verify_2fa_magic_link or stating that start_2fa must precede it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_2fa_magic_linkAInspect
Complete a 2FA challenge using a magic link token (received via email). No code submission needed — the token itself is the proof.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | Magic link token from the verification email |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | |
| action_type | Yes | The action the session was started for: one of `TwoFAActionType` for sessions started through this API; admin-console sessions carry internal values. |
| verified_at | No | |
| already_verified | No | Present (true) when the session had already been verified, by its code or another open of the link; no grant is stored by this call and the grant fields are absent |
| grant_expires_at | No | When the grant this step-up stored stops being accepted |
| grant_single_use | No | Whether the grant is spent by the first act it allows |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false, so the description's added context matters: it discloses that the token is itself the credential, that no secondary code step exists, and that authentication via PROOF_API_KEY or start_login is required. It omits token lifetime/single-use behavior and what a failed verification returns, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core sentence is front-loaded and wastes nothing, and the access requirement is correctly separated into its own block. The phrasing 'a session opens this tool — then call this tool again' is slightly ambiguous about whether the caller is re-entering the same call, which is a small editing blemish rather than bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one simple parameter, an output schema covering return values, and minimal annotations, this is close to complete: purpose, the magic-link vs code distinction, and the auth prerequisite are all present. What an agent still cannot infer is token validity/expiry behavior and the remedy on rejection, which for a one-shot credential tool would be worth one more sentence.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 100% schema coverage, including the description 'Magic link token from the verification email', so the schema does the heavy lifting and baseline is 3. The tool description only reinforces that the token is the proof; it adds no format, length, or expiry semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource ('Complete a 2FA challenge using a magic link token') and immediately separates it from the code-based path that dominates the surrounding 2FA siblings (verify_2fa, submit_verification_code) with 'No code submission needed — the token itself is the proof.' An agent can tell which 2FA-completion tool to pick without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the trigger condition clearly: call this when you hold a magic-link token delivered by email rather than a numeric code, and it documents the access prerequisite (PROOF_API_KEY or an active session from start_login). It stops short of naming the alternative tool (`verify_2fa`) or describing failure conditions such as an expired or already-used token.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_delegationARead-onlyInspect
Verify a Proof of Delegation — the attestation that a domain authorized a specific agent artifact. Pass either the artifact's card (MCP server.json / A2A agent card) or a raw delegation token, PLUS two facts you established yourself: the artifact identity you resolved (the package you are installing, the endpoint you are calling) and the domain you expect to stand behind it. Both are required — a token can be copied into someone else's card, and any domain owner can mint a valid delegation naming someone else's package, so a verdict without both pins would mean 'some domain said something about some artifact'. WHERE THE IDENTITY MAY COME FROM: it is the artifact you are acting on, and never a value read from inside the artifact you are checking. A name in the artifact's own package.json, card or manifest is self-declared and editable by whoever ships it, so checking it against the delegation compares the artifact with itself. Resolve it afresh at call time instead of reusing a value from earlier in this conversation, which may already be stale. When no independently resolvable identity exists — a local or unpublished artifact — you have nothing to compare against, and that is the honest answer: report it rather than a mismatch, because a mismatch here reads as an accusation against the domain named in the delegation. The verifier walks signature → principal → delegate → revocation status, including the cascade down to the domain control proof. Requires no API key. What a verified result means: the expected domain's controller authorized this artifact — NOT that the artifact is safe, audited or endorsed.
| Name | Required | Description | Default |
|---|---|---|---|
| card | No | The MCP server card or A2A agent card to read the delegation from | |
| token | No | A raw delegation token, when you already have it instead of a card | |
| delegate | Yes | The artifact identity you resolved independently. Required: this comparison is what defeats a copied token. | |
| check_status | No | Default true. When false the signature and claims are checked but revocation is NOT — treat the result as "not revoked-checked", never as "not revoked". | |
| expected_principal | Yes | Required. The domain you expect to have authorized this artifact (e.g. postmarkapp.com) — an issuer binds the artifact to nothing, so any domain owner can mint a valid delegation for someone else's package. Without this pin the answer is only "some domain claims this". |
Output Schema
| Name | Required | Description |
|---|---|---|
| reason | No | When not verified: the verifier's failure reason |
| attests | No | When verified: what the delegation attests, in one sentence |
| message | No | When not verified: a readable explanation |
| outcome | No | When not verified: invalid (a genuine negative verdict) or unconfirmed (no confident answer right now) |
| verified | Yes | true when the delegation verified; false is a verdict, read reason and outcome |
| pull_hint | No | Where to pull a re-signed token after key_revoked |
| delegation | No | When verified: the verified claims |
| disclaimer | No | When verified: what the verdict does not say |
| refresh_hint | No | How to refresh the key set |
| status_checked | No | When verified: whether revocation was checked |
| cache_age_seconds | No | How stale the key set is after jwks_stale, in seconds; null when unknown |
| principal_checked | No | When verified: whether the principal was compared with expected_principal |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description adds substantial context beyond that: no API key required, the verification chain walked (signature → principal → delegate → revocation, including the domain control proof cascade), the check_status caveat that a false setting means 'not revoked-checked' not 'not revoked', and an explicit scope limit that a verified result does not mean the artifact is safe or audited.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded correctly — what it does and the required inputs come first — but it runs long and repeats itself: the copied-token rationale appears in the opening paragraph and again in the delegate schema text, and the 'any domain owner can mint a delegation' argument is stated twice. Several clauses could be consolidated without losing any guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description still covers the parts a schema cannot: where the identity may come from, the staleness risk of reusing earlier conversation values, the negative case for local artifacts, and the precise meaning of a positive verdict. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the prose adds real meaning: it explains WHY both delegate and expected_principal are mandatory (a copied token, or a domain minting a delegation for someone else's package), and it constrains the allowed source of the delegate value far beyond the schema's wording.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ("Verify a Proof of Delegation") and defines what the attestation is, so an agent can tell this is a single-token verification rather than a creation or listing operation. It does not, however, name the obvious sibling verify_delegations (batch) or explain the split, leaving that distinction to be inferred.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states what must be passed (card or token PLUS the two self-established pins) and adds a genuine when-not case: for local/unpublished artifacts with no independently resolvable identity, report the absence rather than a mismatch. It stops short of routing to alternative tools (verify_delegations, get_delegation, create_delegation) by name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_delegationsARead-onlyInspect
Batch-verify up to 50 Proof of Delegation artifacts in one call — the inventory half of the checker (h-proof-checker-mcp): re-check everything you already trust instead of one verify_delegation call per artifact. Each item takes the same shape verify_delegation requires (card XOR token, delegate, expected_principal) and follows the same rule about where identity comes from: each delegate is the artifact you are acting on, never a value read from inside the artifact you are checking, and resolved afresh at call time. Items are verified INDEPENDENTLY — no cross-item state, nothing persisted, one item failing never affects another item's result. This tool does NOT discover what you have installed and does NOT fetch anything on your behalf: it verifies material you already hold, the same trust boundary verify_delegation draws. Revocation is always checked (there is no check_status:false here — the point of a batch re-check is to see what changed since you last looked). Each result carries an outcome: confirmed_valid (verified), confirmed_invalid (a genuine negative verdict — revoked, expired, mismatched, malformed, and similar), no_claim_found (the artifact publishes no delegation at all — an absence, never an accusation), or unconfirmed (we could not reach the issuer or otherwise get a confident answer right now — NEVER treat this as a bad verdict). Requires no API key. checked_at on each result is the moment THAT item's own check completed, not one timestamp shared across the call.
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes | 1-50 artifacts to verify in this call, each shaped like a verify_delegation call |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | One result per item, in the order the items were given |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The only annotation is readOnlyHint=true, so the description carries the rest and does so thoroughly: items are verified independently with no cross-item state and nothing persisted, one failing item never affects another, revocation is always checked, and no API key is required. It also defines the outcome vocabulary and warns that unconfirmed must never be read as a negative verdict, and clarifies checked_at is per-item rather than a shared timestamp.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, batch size and the sibling alternative, then behavioral detail and the outcome enum. It is dense but stretches to roughly 250 words with some repetition — 'the same trust boundary verify_delegation draws' and 'the inventory half of the checker' say overlapping things.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still explains the four outcome values and the unconfirmed pitfall, which is exactly the judgment call an agent cannot infer from schema alone. Combined with the trust-boundary constraints on inputs, nothing needed to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description adds some meaning by restating the card-XOR-token rule and the delegate/expected_principal trust logic, plus the cross-item independence guarantee. Much of this duplicates the nested schema descriptions verbatim ('never a value read from inside the artifact you are checking'), so the added value is reinforcement rather than new information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (batch-verify), a specific resource (Proof of Delegation artifacts), and a hard scope limit (up to 50, no discovery, no fetching). It explicitly positions itself against the sibling verify_delegation ('the inventory half of the checker' / 'instead of one verify_delegation call per artifact'), so an agent can route between the batch and single forms without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives both when-to-use ('re-check everything you already trust') and when-not ('does NOT discover what you have installed and does NOT fetch anything on your behalf'), plus the named alternative it replaces. The exclusion of a per-call check_status:false option further constrains usage explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_domainAInspect
Trigger domain verification. Checks DNS records or other verification method to confirm domain ownership.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID to verify |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | Domain record |
| message | Yes | |
| renewed | No | Sent when the call renewed the proof of an already verified domain. |
| verified | Yes | Whether control is confirmed after this call. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, and the description is consistent with a non-destructive trigger. It adds real value by disclosing the auth/session requirement and the two-step 'session opens this tool, then call again' behavior, but says nothing about idempotency, rate limits, how long the check takes, or what happens if records are missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action in the first sentence, then the access caveat. The ACCESS block is slightly dense but every clause is actionable none is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one required parameter, an output schema, and annotations covering the safety profile, the description covers the main hidden barrier (authentication) and the re-invocation pattern. The notable gap is disambiguation from the large family of sibling verification tools, which is the most likely source of misselection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter ('id') and schema description coverage is 100%, with the schema already stating 'Domain ID to verify'. The description adds no meaning beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clear verb+resource: 'Trigger domain verification' plus a one-line explanation that it checks DNS or another method to confirm ownership. It does not, however, distinguish itself from the many near-identical siblings such as start_domain_verification, check_domain_verification, verify_domain_with_credentials, or trigger_verification, so an agent still has to guess which verification tool applies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: you call it on a domain that has been added and needs ownership confirmed. The description adds an important prerequisite chain (needs a Proof account; set PROOF_API_KEY and restart, or sign in with start_login and then re-call this tool), but gives no explicit 'use this instead of X' routing against the crowded verification sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_domain_with_credentialsAInspect
Verify a pending domain using previously stored DNS credentials. Use when credentials are already connected.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Domain ID to verify |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | MongoDB ObjectId |
| domain | Yes | |
| resend | No | Email-sending setup for a domain. Present once email sending has been set up. |
| status | Yes | Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again. |
| proof_id | No | Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry. |
| provider | No | Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major. |
| oauth_url | No | Sent only by the add when Cloudflare sign-in is configured for the detected provider. |
| created_at | Yes | |
| from_email | No | |
| profile_id | No | MongoDB ObjectId |
| updated_at | Yes | |
| check_count | Yes | |
| dns_records | Yes | |
| verified_at | No | |
| proof_status | No | Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation. |
| error_message | No | Why the last check failed. |
| provider_name | Yes | |
| http_file_path | Yes | |
| actual_dns_host | No | The host serving the zone, when it differs from the provider that verified it. |
| last_checked_at | No | |
| oauth_connected | Yes | Whether a Cloudflare connection is stored for this domain. |
| txt_record_name | Yes | |
| for_verification | Yes | |
| has_dns_mismatch | Yes | |
| proof_expires_at | No | When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one. |
| supports_api_key | Yes | |
| txt_record_value | Yes | |
| detected_provider | Yes | The DNS provider read from the nameservers; `unknown` when none matched. |
| for_email_sending | Yes | |
| godaddy_connected | Yes | Whether a GoDaddy connection is stored for this domain. |
| http_file_content | Yes | |
| supports_auto_dns | Yes | Whether the detected provider can create the verification record itself. |
| email_verification | No | An email verification of the domain. The code itself is never returned. |
| supports_api_token | Yes | |
| verified_providers | Yes | Every provider (or `email`) that has confirmed control. |
| verification_method | Yes | `auto_dns`, `manual_dns`, `http_file` or `email`. |
| actual_dns_host_name | No | |
| dns_mismatch_warning | No | Sent only while `has_dns_mismatch` is true. |
| proof_revoked_reason | No | Reason the registry recorded, present only while `proof_status` is `revoked`. |
| verification_subtype | No | How a provider verified the domain: by creating the record, or by confirming ownership without one. |
| email_sending_enabled | No | Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major. |
| has_provider_credentials | No | Sent only by the add: the account already holds credentials for the detected provider. |
| provider_credential_name | No | Sent only by the add, with `has_provider_credentials`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false, so the description carries most of the weight, and it does add real context: a stored-credential prerequisite, an account/API-key requirement, and the start_login recovery path. It still omits what the verification actually does on the DNS side, failure behavior, and whether re-calling is idempotent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences establish purpose and precondition up front, then a labeled ACCESS block covers auth. Slightly redundant phrasing ('a session opens this tool — then call this tool again') costs it a perfect score but nothing is wasted overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description covers the two things an agent would otherwise get wrong: the stored-credentials prerequisite and the auth setup path. The remaining gap is what to do when the prerequisite is unmet other than signing in.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 100% schema description coverage ('Domain ID to verify'), so the schema already fully documents it. The description adds no syntax, format, or sourcing detail for the id, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource plus the distinguishing mechanism: 'Verify a pending domain using previously stored DNS credentials.' An agent can separate it from verify_domain and start_domain_verification by the credential source, though the description never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use when credentials are already connected' gives an explicit precondition that selects this tool over its credential-free siblings, and the ACCESS paragraph states the account requirement. It falls short of 5 because it never names the alternative to use when no credentials exist (e.g. connect_dns_provider or verify_domain).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_email_otpAInspect
Submit the OTP code to verify an email addition. Completes the add-email flow if the code is correct.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, or sign in with start_login — a session opens this tool — then call this tool again.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | OTP code received via email | |
| session_id | Yes | Add-email session ID |
Output Schema
| Name | Required | Description |
|---|---|---|
| Yes | ||
| status | Yes | |
| verified_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, and the description adds that this submission is the completing step of a multi-step add-email flow and requires an authenticated Proof account. It says nothing about behavior on an incorrect, expired, or already-used code, nor whether attempts are rate limited.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action is front-loaded in the first sentence, and the access prerequisites are separated into their own labeled block so they can be skipped on a re-read. Minor redundancy in "verify an email addition" / "add-email flow", but nothing that wastes the agent's attention.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only two required parameters, full schema descriptions, an output schema, and annotations covering the safety profile, the definition covers what an agent needs to make the call. The remaining gap is failure handling — what a rejected code looks like and whether re-submission is allowed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (session_id, code) carry their own descriptions, so the schema does the heavy lifting. The description ties the code to the add-email flow but adds no format, length, or expiry detail beyond what the schema states. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ("Submit the OTP code to verify an email addition") and names the flow it terminates ("Completes the add-email flow"), which situates it against a large sibling set. It does not explicitly name the adjacent tools (start_add_email, resend_email_otp, get_add_email_status), but the flow framing lets an agent place it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The ACCESS paragraph gives concrete prerequisites — either set PROOF_API_KEY and restart, or run start_login, which "opens this tool", then retry. That is real invocation guidance rather than vague context. It stops short of stating when to prefer resend_email_otp or what to do when the code is wrong, so no alternative routing is offered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_2faARead-onlyInspect
Poll a 2FA session until the user completes the challenge. Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
Agent usage: Call this after start_2fa with the returned session_id. Terminal states: "verified" (challenge completed — proceed with the protected operation), "expired" (offer to restart with start_2fa). Before polling, present start_2fa's challenge: pass its deep_link to render_auth_link on telegram/whatsapp, or show its sms_message on sms.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | 2FA session ID from start_2fa | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 600). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| session_id | No | |
| action_type | No | The action the session was started for: one of `TwoFAActionType` for sessions started through this API; admin-console sessions carry internal values. |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| verified_at | No | |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
| grant_expires_at | No | When the grant this step-up stored stops being accepted |
| grant_single_use | No | Whether the grant is spent by the first act it allows |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, consistent with polling. The description adds substantial context beyond that: exponential backoff parameters, the pending-on-timeout behavior and retry instruction, the access prerequisite (PROOF_API_KEY), and the important caveat that users do not see tool results so the link/SMS text must be echoed in the reply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded: core behavior first, then agent usage, then a UX caveat and access note. Slightly long, and the final ACCESS sentence about start_login not opening the tool is a bit tangential, but every paragraph carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter polling tool with an output schema, this covers everything needed: preconditions, terminal states, timeout semantics, rendering requirements, and auth setup. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds provenance for session_id (from start_2fa) and explains the consequence of timeout_seconds expiring (status 'pending', call again), which goes beyond the schema's warning about client request timeouts.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource: 'Poll a 2FA session until the user completes the challenge.' This is clearly distinct from sibling pollers like get_2fa_status and wait_for_login because the object (a 2FA session started by start_2fa) is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the precondition ('Call this after start_2fa with the returned session_id'), enumerates terminal states and the follow-up action for each ('expired' → restart with start_2fa), and tells the agent to render the challenge via render_auth_link before polling. When-to-use and what-to-do-next are both explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_account_creationARead-onlyInspect
Poll an account-bootstrap session until the user completes verification. Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
Agent usage: Call this after create_account with the returned session id. Terminal states: "verified" (this server keeps the session for this connection; the user_id field in the terminal body identifies the authenticated user), "expired", "completed_elsewhere" (email only: the user pressed "Sign in here" on the email link's page, so the browser they clicked from is signed in and this connection never will be — tell them so, and start a new login if this connection still needs one). A result with status "pending" means the wait ran out before the user finished — call this tool again with the same id. Works identically whether the underlying flow created a new User or logged in an existing one.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Account session id from create_account | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 600). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| type | No | Outcome of an account-session creation. `account_creation` means a new User will be written on verification. `login` indicates the submitted identity matched an existing User and the session will log them in. |
| No | ||
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| channel | No | Authentication channel |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| qr_code | No | Base64-encoded PNG QR code for the deep link |
| qr_text | No | UTF-8 text QR for terminal/agent rendering |
| user_id | No | |
| sms_code | No | Short code for SMS-channel reverse-OTP |
| deep_link | No | |
| created_at | No | |
| email_sent | No | |
| expires_at | No | |
| email_error | No | |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| sms_message | No | |
| verified_at | No | |
| instructions | No | |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation: it discloses the polling cadence (2s initial, 1.5x growth, 30s cap, jitter), the semantic difference between the three terminal states, that the server keeps the session bound to this connection, and that the flow behaves identically for new vs. existing users. No contradiction with readOnlyHint — the tool waits and reads, it does not itself mutate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verb and the backoff profile, then the agent-usage paragraph, then the caveat — a sensible ordering. The final paragraph about showing the link in reply text is slightly tangential to invocation but does earn its place as a precondition; overall it is denser than most descriptions but nearly every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return shape needn't be re-explained, yet the description still names the terminal statuses and the `user_id` field that identifies the authenticated user. Combined with the timeout/pending retry semantics, an agent has everything needed to call this in a loop and interpret every outcome.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents both `id` and `timeout_seconds`, including the 50s default, 600s max, client-timeout caveat and the "call again with the same identifier" behavior on pending. The description reinforces the reuse-the-same-id rule for retries but adds no new meaning about parameter format or values, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific verb (poll), the specific resource (account-bootstrap session) and the terminating condition (user completes verification), which cleanly separates it from wait_for_login, wait_for_session and wait_for_verification. The follow-up sentence "Call this after create_account with the returned session id" pins it into the flow where an agent would otherwise hesitate between several wait_* siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger (after create_account), an explicit retry rule (status "pending" means call again with the same id), and enumerated terminal states with a prescribed agent action for the tricky one ("completed_elsewhere" → tell the user the browser is signed in but this connection never will be). It also adds a precondition: surface the link/SMS/inbox note in assistant text before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_chat_id_discoveryARead-onlyInspect
Poll a chat ID discovery token until the user interacts with the Telegram bot. Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
Agent usage: Call this after create_chat_id_discovery. Present the discovery response's deep_link with render_auth_link first, then poll with the returned token. Terminal states: "completed" (chat_id discovered — use it when creating a HITL config with a Telegram channel), "expired". While "pending", the user has not yet opened the Telegram link.
The user does not see tool results — most clients fold them away, render_auth_link's output included. Before you wait or poll, put what the user must act on into your own reply text: the link itself (not a sentence announcing it), the SMS text and number, or a note to check their inbox.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| token | Yes | Discovery token from create_chat_id_discovery | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 600). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| chat_id | No | |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, it discloses the backoff profile (2s, 1.5x, 30s max, jitter), the pending-on-timeout behavior, and the fact that clients fold away tool output so the agent must surface the link or code in its own reply. That is exactly the operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and polling behavior come first, followed by the usage recipe and terminal states. The ACCESS paragraph is somewhat dense and its 'start_login does NOT open this tool' line is tangential, but overall every section carries actionable content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter polling tool with an output schema, the description covers prerequisites, sequencing, terminal states, timeout retry behavior and the proof-account requirement — nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are already documented in the schema, including the timeout rationale. The description only adds token provenance ('returned token' from the create call), which is largely duplicative, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — polling a chat ID discovery token until the Telegram user interacts — and names the creating sibling create_chat_id_discovery. It does not distinguish itself from the close sibling poll_chat_id_discovery, so the agent must infer which of the two to call.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit sequence (create_chat_id_discovery, then render_auth_link with the deep_link, then poll with the returned token) and names the terminal states completed/expired and the pending meaning. The only gap is no guidance on when to use this versus poll_chat_id_discovery.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_confirmationARead-onlyInspect
Poll a confirmation until the approver responds. Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
Agent usage: Call this after create_confirmation with the returned confirmation ID. Terminal states: "approved" (action authorized — check the proof_token), "denied" (action rejected). While "pending", the approver has not yet responded. This poll returns no link — the approval request is delivered to the approver's own channel, and only the owner's "Send again" (POST /api/v1/confirmations/{id}/resend, which no tool calls yet) delivers it there again. If the owner will decide instead, call get_confirmation_approval_link for the owner's approval_url; it needs the confirmation to be still pending — the state this tool waits in — and also refuses once timeout_at has passed, so a long wait can outlive the link even while the status has not moved.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Confirmation ID from create_confirmation | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 600). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| hitl_id | No | |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| resends | No | Every "Send again" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it. |
| response | No | The decision and its evidence (null while pending) |
| created_at | No | |
| timeout_at | No | When this confirmation will time out |
| updated_at | No | |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| proof_token | No | Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`) |
| resolved_at | No | |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, and the description is consistent with a non-mutating poll while adding substantial behavior: exponential backoff parameters (2s initial, 1.5x, 30s max, jitter), what 'pending' means, that the call returns no link and the request is delivered to the approver's own channel, and the resend path that no tool currently covers. It also discloses the auth prerequisite (PROOF_API_KEY) and that start_login cannot satisfy it, which is behavior the annotations do not carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and backoff behavior, then clearly sectioned into 'Agent usage:' and 'ACCESS:'. The aside about the resend endpoint and the parenthetical 'which no tool calls yet' is useful context but is the one passage that could be trimmed without losing callable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a polling tool with an output schema, the description covers everything an agent needs: when to start, what states to expect, how long to wait relative to client timeouts, what is not returned, and the account prerequisite. Return-value documentation is correctly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both id and timeout_seconds are already fully documented, including the under-client-timeout advice. The description reinforces the id's origin ('from create_confirmation') but adds no format, value, or edge-case detail beyond the schema, which is the expected baseline when the schema does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Poll a confirmation') plus the exact condition bounding it ('until the approver responds'). It also enumerates the terminal states (approved/denied) and names the sibling it is not (get_confirmation_approval_link), so an agent can distinguish it from the other confirmation tools without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition ('Call this after create_confirmation with the returned confirmation ID') and a named alternative with the condition that selects it ('If the owner will decide instead, call get_confirmation_approval_link'). It also states an exclusion ('start_login does NOT open this tool') and warns that the link path fails once timeout_at passes while this tool keeps waiting.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_loginARead-onlyInspect
Poll a login session until the user completes authentication. Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
Agent usage: Call this after start_login with the returned session ID. Terminal states: "verified" (login succeeded — this server keeps the session for this connection and signs your own account records with it: emails, phones, domains, API keys, 2FA, DNS credentials, verification requests, your public profile's username and proof list), "failed", "expired", "completed_elsewhere" (email only: the user pressed "Sign in here" on the email link's page, so the browser they clicked from is signed in and this connection never will be — tell them so, and start a new login if this connection still needs one). A result with status "pending" means the wait ran out before the user finished — call this tool again with the same id.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Auth session ID from start_login | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 600). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| type | No | |
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| channel | No | Authentication channel |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| qr_code | No | Base64-encoded QR code image |
| qr_text | No | UTF-8 text representation of the QR code for terminal/agent display |
| user_id | No | |
| deep_link | No | |
| expires_at | No | |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| verified_at | No | |
| instructions | No | |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true; the description goes far beyond by disclosing the backoff schedule (2s initial, 1.5x, 30s max, jitter) and enumerating all four terminal states with consequences. The "completed_elsewhere" explanation (email-only, browser becomes signed in, this connection never will, start a new login) is exactly the kind of non-obvious behavioral context an agent cannot infer elsewhere.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and backoff, then a labelled "Agent usage:" block that keeps the guidance scannable. The terminal-state sentence is dense and parenthetical, but every clause carries distinct information (state name, meaning, required agent action).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full lifecycle an agent needs: prerequisite tool, polling/retry semantics, all terminal outcomes and what to do for each, and the user-facing side effect of showing the challenge link. With an output schema present, no return-shape explanation is required and none is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented. The description still adds value by framing the id as reusable across retries and explaining that a wait exceeding the client's request timeout surfaces as "pending" rather than a failure — reinforcing the schema's timeout note with operational intent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: "Poll a login session until the user completes authentication." It is clearly distinguishable from the many sibling waiters (wait_for_2fa, wait_for_session, wait_for_verification) because it names the login-session object and ties it to start_login's returned ID.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the sequencing ("Call this after start_login with the returned session ID") and gives a retry rule: a "pending" result means call again with the same id. It also adds a pre-call obligation — surface the link/SMS/inbox note in the reply text before polling — which is real routing guidance, not filler.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_requestARead-onlyInspect
Poll a verification request until it reaches a terminal state (completed, expired, or cancelled). Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification request ID to poll | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 300). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| assets | No | |
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| progress | No | |
| created_at | No | |
| expires_at | No | |
| partial_ok | No | |
| updated_at | No | |
| action_type | No | Type of action for verification request or authorization |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| callback_url | No | The webhook URL set on the request, if any |
| completed_at | No | |
| redirect_url | No | |
| reference_id | No | |
| action_context | No | The action the person is asked to authorize; null when the request carries none |
| computed_state | No | Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces. |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
| verification_url | No | URL for the verification flow |
| validity_requirement | No | Required proof freshness as set on the request (e.g. "7d"); null when none was set |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the rest and does it well: the exponential backoff schedule (2s initial, 1.5x, 30s max), jitter, the terminal-state set, and the concrete timeout return value of "pending". The PROOF_API_KEY requirement and restart instruction are behavior an agent cannot infer from schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks with the core behavior first and the prerequisite second; every sentence carries information about polling, timing, or access. The quoted ACCESS block is slightly heavy for what it conveys but is not wasted given the tool is otherwise unusable without the key.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no prose, and the description still covers the one non-obvious return case (status "pending" on timeout). Auth and timing are covered; the only real gap is disambiguating this waiter from the several other wait_for_* and get_verification_request tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning: the backoff ceiling explains why short timeouts are cheap, and "call it again with the same identifier" clarifies that id is stable across retries rather than a one-shot handle. The interaction between timeout_seconds and the client-side request timeout is the key semantic and it is surfaced.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: poll a verification request until it reaches a terminal state, and enumerates those states (completed, expired, cancelled). It does not name the sibling it replaces, so an agent still has to guess between this, wait_for_verification, wait_for_session, and a manual get_verification_request loop.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives real operational guidance — keep timeout_seconds under the client timeout, and on "pending" call again with the same identifier — plus an access prerequisite that start_login does not unlock this tool. What is missing is the when-to-use-vs-alternatives statement: nothing says why to prefer this over get_verification_request or wait_for_verification.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_sessionARead-onlyInspect
Poll a session until it reaches a terminal state (verified, failed, or expired). Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Session ID to poll | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 300). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | Session id |
| proof | No | Proof token after successful verification |
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| channel | No | How the person proves the number: `telegram` or `whatsapp` (the bot reads the number from their account), or `sms` (they text a short code from the number to one of ours). |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| created_at | No | |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| verified_at | No | Once `verified` |
| phone_number | No | The proven number (once `verified`) |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
| verification_id | No | The verification record created on completion (once `verified`) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description is consistent with that while adding real behavior: exponential backoff (2s initial, 1.5x, 30s max) with jitter, and the timeout contract where the tool returns status 'pending' and must be re-called with the same identifier. The UX caveat about links appearing only in a tool result is a non-obvious behavioral trap that structured fields cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the function and its terminal states, then polling mechanics, then the reply-text prerequisite. Three short blocks with no filler; the user-facing-reply paragraph is slightly digressive but earns its place by preventing an unusable result.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description still covers the one return case that matters operationally (timeout yields 'pending'). Prerequisites, blocking duration bounds, and retry instructions are all present for a two-parameter polling tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the timeout semantics (default 50, max 300, client timeout interaction, re-call on pending) are already written in the schema property description rather than in the tool description. The description adds no parameter meaning beyond that, which is the correct baseline when the schema does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Poll a session') and enumerates the terminal states (verified, failed, expired), which is far more than a restatement of the name. It never names the non-blocking sibling get_session, so an agent must infer the blocking-vs-single-check distinction rather than being told it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use context: call it after creating a challenge, and only after the user-facing reply already contains the actionable link/text. The access note ('needs a Proof account... start_login does NOT open this tool') pre-empts a likely wrong path. It stops short of explicitly saying 'use get_session if you do not want to block'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_verificationARead-onlyInspect
Poll a verification until it reaches a terminal state (verified, failed, expired, revoked, or cancelled). Uses exponential backoff (2s initial, 1.5x, 30s max) with jitter.
A multi-channel verification that lost the race is "cancelled" and one whose proof was withdrawn is "revoked"; both are final, so the wait returns rather than polling on.
Before calling this for a challenge you created, make sure your reply text already shows the user what to act on — the link itself, the SMS text and number, or a note to check their inbox; a link that appeared only in a tool result is one they never saw.
ACCESS: needs a Proof account. Set PROOF_API_KEY and restart this server, then call this tool again. start_login does NOT open this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Verification ID to poll | |
| timeout_seconds | No | Maximum wait time in seconds (default: 50, max: 300). Keep it under your MCP client's request timeout (the SDK default is 60 s) — a longer wait is cut off by the client while the server is still polling. On timeout the tool answers status "pending"; call it again with the same identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | MongoDB ObjectId |
| type | No | Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account. |
| proof | No | Proof token after successful verification |
| status | No | "pending" when the wait ran out before a terminal state; otherwise the resource's own status |
| channel | No | Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken. |
| message | No | On timeout: what to do next (call the tool again with the same identifier) |
| attempts | No | |
| challenge | No | Challenge details for verification |
| created_at | No | |
| identifier | No | The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it |
| updated_at | No | |
| last_status | No | On timeout: the last non-terminal status observed, or null when none was |
| verified_at | No | |
| max_attempts | No | |
| waited_seconds | No | On timeout: seconds actually waited |
| timeout_seconds | No | On timeout: the wait budget this call was given |
| external_user_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint=true: it discloses the backoff curve (2s initial, 1.5x, 30s max) with jitter, the timeout contract (returns status "pending", re-call with the same id), and the access prerequisite (PROOF_API_KEY plus server restart, and that start_login does not enable it). The UX warning about the link needing to appear in reply text rather than only in a tool result is a genuinely non-obvious behavioral constraint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core behavior and the polling mechanics, then conditions and prerequisites. The middle paragraph on cancelled vs revoked is earned because it explains why the wait returns, though the access note about start_login reads slightly like a tangent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, return values need not be described, and the description covers timing, terminal states, timeout recovery, and auth prerequisites. The remaining gap is relational: it never says how this differs from the other wait_* and get_* verification siblings in the same family.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already documents the id and the full timeout_seconds range, default, and client-timeout caveat. The description adds no parameter-level meaning beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Poll a verification until it reaches a terminal state") and enumerates the five terminal states, which is far more precise than the name alone. It stops short of naming which sibling it replaces (get_verification, get_multi_channel_verification_status, wait_for_request), so the boundary with those tools is only implied.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete precondition for use ("Before calling this for a challenge you created, make sure your reply text already shows the user what to act on") and explains why the wait returns early on cancelled/revoked rather than continuing. It does not state when to prefer this over a one-shot status call such as get_verification, so the choice between polling and waiting is left to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
179 tool updates
v1.7.2- Changed
add_circle_member2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "enrolled_at": {}, + "enrolled_phone_hint": { + "description": "Masked form of the phone the contact proved when they enrolled (the Telegram shared contact or the WhatsApp sender) — country prefix and last four digits only, never the full number. Lets the owner see who actually joined. Null until the member enrolls, and for members enrolled before it was recorded." + }, + "has_telegram": { + "description": "Whether the member has a Telegram channel (declared or verified)" + }, + "has_whatsapp": { + "description": "Whether the member has a WhatsApp channel (declared or verified)" + }, + "id": { + "description": "MongoDB ObjectId" + }, + "last_verified_at": { + "description": "When this member last CONFIRMED an identity check asked of them — i.e. last proved it was them. Null until they have." + }, + "mesh_opt_out": { + "description": "The member sent /opt_out: they receive no drills, reminders or checks they did not start themselves" + }, + "mesh_opted_in": {}, + "name": {}, + "status": {} + }, + "type": "object" +}
- Changed
add_circle_member_channel2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": {}, + "created_at": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "status": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
add_domain3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (24 hex characters) whose email settings this domain is for", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
add_verification_provider3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / credentials / propertyNamesAdded value: +{ + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
cancel_user_request2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
cancel_verification_request2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "status", + "message" + ], + "type": "object" +}
- Changed
check_domain_credentials2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Which of the account's DNS credentials can reach a domain", + "properties": { + "accessible_credentials": { + "items": { + "additionalProperties": {}, + "properties": { + "error": { + "type": "string" + }, + "has_access": { + "type": "boolean" + }, + "is_registrar": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "provider": { + "type": "string" + } + }, + "required": [ + "provider", + "name", + "has_access" + ], + "type": "object" + }, + "type": "array" + }, + "can_try_ownership_verification": { + "description": "A registrar credential can confirm ownership while the zone is served elsewhere.", + "type": "boolean" + }, + "detected_provider": { + "type": "string" + }, + "has_accessible_credential": { + "type": "boolean" + }, + "has_credentials": { + "description": "Whether the account holds any valid DNS credential. When false, only `accessible_credentials` (empty), `detected_provider` and `suggestion` are sent.", + "type": "boolean" + }, + "has_registrar_credentials": { + "type": "boolean" + }, + "registrar_provider": { + "type": "string" + }, + "suggestion": { + "description": "Sent when no credential can reach the domain.", + "type": "string" + } + }, + "required": [ + "has_credentials", + "accessible_credentials", + "detected_provider" + ], + "type": "object" +}
- Changed
check_domain_email_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
check_domain_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "check_count": {}, + "domain": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "status": {}, + "verified": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
check_user_domain_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The result of one check of the published record or file", + "properties": { + "asset": { + "additionalProperties": {}, + "description": "The domain asset holding the proof; present when `status` is `verified`", + "properties": { + "id": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "proof_expires_at": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "identifier" + ], + "type": "object" + }, + "message": { + "description": "Why the check is still pending; present when `status` is `pending`", + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "description": "Present when `status` is `verified`", + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" +}
- Changed
claim_username2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The claimed username", + "properties": { + "profile_url": { + "description": "Path of the public profile", + "type": "string" + }, + "username": { + "type": "string" + }, + "username_claimed_at": { + "type": "string" + } + }, + "required": [ + "username", + "username_claimed_at", + "profile_url" + ], + "type": "object" +}
- Changed
confirm_domain_email_code2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The domain after a verification check, by DNS or by an emailed code", + "properties": { + "data": { + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "type": "string" + }, + "dns_mismatch_warning": { + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "type": "boolean" + }, + "oauth_url": { + "type": "string" + }, + "profile_id": { + "type": "string" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "provider_credential_name": { + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "type": "string" + }, + "verification_subtype": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "message": { + "type": "string" + }, + "renewed": { + "description": "Sent when the call renewed the proof of an already verified domain.", + "type": "boolean" + }, + "verified": { + "description": "Whether control is confirmed after this call.", + "type": "boolean" + } + }, + "required": [ + "data", + "verified", + "message" + ], + "type": "object" +}
- Changed
connect_cloudflare2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
connect_dns_provider3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / credentials / propertyNamesAdded value: +{ + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
connect_godaddy2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
create_account3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / email / patternAdded value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "Authentication channel" + }, + "created_at": {}, + "deep_link": {}, + "email": {}, + "email_error": {}, + "email_sent": {}, + "expires_at": {}, + "id": {}, + "instructions": {}, + "qr_code": { + "description": "Base64-encoded PNG QR code for the deep link" + }, + "qr_text": { + "description": "UTF-8 text QR for terminal/agent rendering" + }, + "sms_code": { + "description": "Short code for SMS-channel reverse-OTP" + }, + "sms_message": {}, + "status": { + "description": "Status of an auth session. `completed_elsewhere` (terminal, no cookies): an email sign-in the person completed in ANOTHER browser by pressing \"Sign in here\" on the link's page — this session will never become `verified`." + }, + "type": { + "description": "Outcome of an account-session creation. `account_creation` means a new User will be written on verification. `login` indicates the submitted identity matched an existing User and the session will log them in." + }, + "user_id": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
create_api_key3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"Bind the new key to a sub-account (PublicProfile) project you own (24-hex id). Immutable after creation; omit for an unbound account-wide key."New value: +"Bind the new key to a sub-account you own (24-hex id). Immutable after creation; omit for an unbound account-wide key." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A newly created or regenerated API key, with its full value — the one response that carries it.", + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "key": { + "description": "The full API key. Returned only in this response; it cannot be read again.", + "type": "string" + }, + "name": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "profile_id": { + "description": "Sub-account (PublicProfile) the key is bound to; null for unbound keys.", + "type": [ + "string", + "null" + ] + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "warning": { + "type": "string" + } + }, + "required": [ + "id", + "key", + "name", + "prefix", + "environment", + "scopes", + "profile_id", + "created_at", + "warning" + ], + "type": "object" +}
- Changed
create_authorization5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / business_name / descriptionPrevious value: -"Business name displayed to user during authorization"New value: +"Deprecated and ignored: the consent message always names the approval setup's sub-account. Leave it out." - changed
Input schema / properties / business_profile_id / descriptionPrevious value: -"Public profile ID for branding"New value: +"Sub-account to record on the authorization (does not change the name the person sees)" - changed
Input schema / requiredPrevious value: -[ - "hitl_id", - "recipient", - "phone", - "channel", - "business_name" -]New value: +[ + "hitl_id", + "recipient", + "phone", + "channel" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Response from creating an authorization request", + "properties": { + "authorization_url": { + "description": "URL to send to the user for authorization", + "type": "string" + }, + "bsuid": { + "description": "WhatsApp Business-Scoped User ID", + "type": [ + "string", + "null" + ] + }, + "business_name": { + "description": "The name the consent message carried: the approval setup's sub-account name, never a name typed in the request.", + "type": "string" + }, + "channel": { + "description": "Channel authorized for sending confirmations", + "type": "string" + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "hitl_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "phone": { + "type": [ + "string", + "null" + ] + }, + "recipient": { + "description": "Channel-specific recipient identifier (chat_id for Telegram, phone or BSUID for WhatsApp)", + "type": [ + "string", + "null" + ] + }, + "scope": { + "description": "Scope of the authorization. `identity_challenge` is the Proof of Me scope.", + "type": "string" + }, + "status": { + "description": "Status of an authorization", + "type": "string" + } + }, + "required": [ + "id", + "status", + "hitl_id", + "channel", + "scope", + "business_name", + "authorization_url", + "expires_at", + "created_at" + ], + "type": "object" +}
- Changed
create_chat_id_discovery1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Chat ID discovery token and Telegram deeplink", + "properties": { + "deep_link": { + "type": "string" + }, + "expires_in": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "qr_code": { + "description": "QR code data URL for the deep link", + "type": "string" + }, + "qr_text": { + "description": "UTF-8 text representation of the QR code for terminal/agent display", + "type": "string" + }, + "token": { + "type": "string" + } + }, + "required": [ + "token", + "deep_link", + "qr_code", + "qr_text", + "expires_in" + ], + "type": "object" +}
- Changed
create_circle3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / members / items / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "created_at": {}, + "environment": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "member_count": {}, + "members": {}, + "name": {}, + "owner_name": { + "description": "How this Circle's members know its owner; null when unset" + }, + "profile_id": {}, + "proof_me_enabled": {}, + "status": { + "description": "Lifecycle state of a Circle (archived = soft-retired)" + }, + "updated_at": {}, + "user_id": {} + }, + "type": "object" +}
- Changed
create_circle_member_drill2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "confirm_channel": { + "description": "Channel the CONFIRM was dispatched on" + }, + "id": {}, + "single_channel_warning": { + "description": "True when the owner has only one channel, so the CONFIRM ran on the same channel (degraded)" + }, + "status": {} + }, + "type": "object" +}
- Changed
create_confirmation4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / proof_expiry_days / maximumAdded value: +9007199254740991 - added
Input schema / properties / proof_expiry_days / minimumAdded value: +-9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "created_at": {}, + "hitl_id": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "message": { + "description": "The stored ciphertext envelope, echoed back verbatim. The server never sees the plaintext, so this is never the human sentence — the approver decrypts it in their browser." + }, + "proof_token": { + "description": "Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`)" + }, + "resends": { + "description": "Every \"Send again\" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it." + }, + "resolved_at": {}, + "response": { + "description": "The decision and its evidence (null while pending)" + }, + "status": { + "description": "Status of a confirmation request. A confirmation that times out is `denied`, with `response.channel` `system` and `response.text` `timeout`." + }, + "timeout_at": { + "description": "When this confirmation will time out" + }, + "updated_at": {} + }, + "type": "object" +}
- Changed
create_delegation5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / delegate / additionalPropertiesRemoved value: -false - removed
Input schema / properties / scopeRemoved value: -{ - "description": "1-32 capability scopes: lowercase kebab-case tokens, at most 64 characters each (e.g. send-email). NOT API scopes — an API-style resource:action such as payments:read is rejected with invalid_scope.", - "items": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "maxItems": 32, - "minItems": 1, - "type": "array" -} - changed
Input schema / requiredPrevious value: -[ - "control_proof", - "delegate", - "scope" -]New value: +[ + "control_proof", + "delegate" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "control_proof": { + "description": "The control proof handle this delegation points down to" + }, + "created_at": {}, + "delegate": { + "description": "Typed delegate identifier" + }, + "delegation_id": { + "description": "Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint" + }, + "effective_status": { + "description": "DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects" + }, + "environment": {}, + "expires_at": { + "description": "Never later than the control proof's own expiry at issuance (effective expiry is min of the two)" + }, + "id": { + "description": "MongoDB ObjectId" + }, + "is_valid": { + "description": "True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above" + }, + "issued_at": {}, + "principal": { + "description": "The proven domain that authorized the delegate — derived from the control proof, never client input" + }, + "revoked_at": {}, + "revoked_reason": {}, + "scope": { + "description": "Deprecated. Delegation schema 2.0 carries no scope; this array stays for the SDKs released before it: the scope a delegation issued before schema 2.0 was stored with, otherwise empty. Removed in the next major version." + }, + "status": { + "description": "The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on" + }, + "token": { + "description": "The signed delegation JWT — the PUBLISHABLE artifact (publish it in your MCP server card under `_meta` → `holdings.proof/delegation`). Same key, algorithm and JWKS as proof tokens" + } + }, + "type": "object" +}
- Changed
create_dns_credential3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / credentials / propertyNamesAdded value: +{ + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A saved DNS provider credential. The secret is never returned.", + "properties": { + "created_at": { + "type": "string" + }, + "domains_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_valid": { + "type": "boolean" + }, + "last_used_at": { + "description": "When the credential last made a DNS change; absent until it has. Sent by the list only.", + "type": "string" + }, + "last_validated_at": { + "description": "When the credential was last checked against its provider; absent when never recorded. Sent by the list only.", + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "validation_error": { + "description": "Why the last check refused the credential; absent unless one did. Sent by the list only.", + "type": "string" + } + }, + "required": [ + "id", + "provider", + "name", + "is_valid", + "domains_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
create_hitl8 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / channels / descriptionPrevious value: -"Messaging channels for approval requests (telegram or whatsapp)"New value: +"Messaging channels for approval requests (telegram or whatsapp). Either channels or circle_id is required." - removed
Input schema / properties / channels / items / anyOfRemoved value: -[ - { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": false, - "properties": { - "chat_id": { - "maxLength": 50, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "chat_id" - ], - "type": "object" - }, - "type": { - "const": "telegram", - "type": "string" - } - }, - "required": [ - "type", - "config" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": false, - "properties": { - "bsuid": { - "description": "WhatsApp Business-Scoped User ID (e.g. US.abc123...)", - "pattern": "^[A-Z]{2}\\.[a-zA-Z0-9]{10,140}$", - "type": "string" - }, - "phone_number": { - "description": "Phone number in E.164 format", - "pattern": "^\\+?[1-9]\\d{6,14}$", - "type": "string" - } - }, - "type": "object" - }, - "type": { - "const": "whatsapp", - "type": "string" - } - }, - "required": [ - "type", - "config" - ], - "type": "object" - } -] - added
Input schema / properties / channels / items / oneOfAdded value: +[ + { + "properties": { + "config": { + "properties": { + "chat_id": { + "maxLength": 50, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "properties": { + "config": { + "properties": { + "bsuid": { + "description": "WhatsApp Business-Scoped User ID (e.g. US.abc123...)", + "pattern": "^[A-Z]{2}\\.[a-zA-Z0-9]{10,140}$", + "type": "string" + }, + "phone_number": { + "description": "Phone number in E.164 format", + "pattern": "^\\+?[1-9]\\d{6,14}$", + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } +] - added
Input schema / properties / circle_idAdded value: +{ + "description": "Route approvals through this circle's members instead of listed channels (24 hex characters)", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (24 hex characters) whose branding the approval messages carry; omitted, the primary", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "name", - "channels" -]New value: +[ + "name" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "HITL configuration with messaging channels and timeout", + "properties": { + "channels": { + "items": { + "oneOf": [ + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "chat_id": { + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "bsuid": { + "type": "string" + }, + "phone_number": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } + ] + }, + "type": "array" + }, + "circle_id": { + "description": "Backing Circle for a circle-backed Approvals config (null for channel-list configs)", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "keypair": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "has_backup_wrapper": { + "type": "boolean" + }, + "has_encrypted_private_key": { + "type": "boolean" + }, + "has_wrapped_dek": { + "type": "boolean" + }, + "kid": { + "type": "string" + } + }, + "required": [ + "kid", + "has_encrypted_private_key", + "has_wrapped_dek", + "has_backup_wrapper" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Encryption keypair metadata (null if not configured)" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Status of a HITL configuration", + "type": "string" + }, + "timeout_seconds": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "description": "Owner user ID (useful for SDK encryption AAD)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "channels", + "timeout_seconds", + "status", + "keypair", + "environment", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
create_identity_challenge2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "An identity challenge (Proof of Me)", + "properties": { + "channel": { + "description": "Channel the CONFIRM was dispatched on (GET)", + "type": "string" + }, + "circle_id": { + "description": "The Circle the check belongs to (GET)", + "type": [ + "string", + "null" + ] + }, + "confirm_channel": { + "description": "Channel the CONFIRM was dispatched on (POST)", + "type": "string" + }, + "created_at": { + "description": "ISO 8601 timestamp", + "type": "string" + }, + "expires_at": { + "description": "ISO 8601 timestamp", + "type": "string" + }, + "id": { + "type": "string" + }, + "is_drill": { + "description": "True for a drill (scheduled, or started from the dashboard) rather than a real check (GET)", + "type": "boolean" + }, + "proof_id": { + "description": "Public handle of the decision's proof — what `POST /proofs/{proof_id}/revoke` takes. Null until a decision minted one (GET).", + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "description": "Signed proof token, present once the person being checked decided", + "type": [ + "string", + "null" + ] + }, + "resolved_at": { + "description": "ISO 8601 timestamp of the decision — the CONFIRM, the DENY, the cancellation or the delivery failure — or null while the check is unanswered and after a timeout.", + "type": [ + "string", + "null" + ] + }, + "single_channel_warning": { + "description": "True when the account holder has only one channel, so the CONFIRM ran on the same channel as the suspicious contact (degraded)", + "type": "boolean" + }, + "status": { + "description": "The one status every read reports. `pending` — waiting for the person being checked; `confirmed` — they confirmed; `denied` — they denied; `cancelled` — whoever started the check withdrew it; `failed` — the check could not be delivered; `expired` — nobody answered in time; `revoked` / `suspended` — the confirmation's proof was revoked or suspended (`POST /proofs/{proof_id}/revoke` or `/suspend`; revoking a denial's proof leaves it `denied`), or — `revoked` only — the member being checked was removed from the Circle while the check was still pending, which leaves `proof_id` null. Removing a member is not guaranteed to revoke a confirmation they already gave; revoke that one by its `proof_id`. A proof that merely reached its own expiry still reads `confirmed`; whether its token is still valid is `POST /proofs/validate`'s answer.", + "type": "string" + } + }, + "required": [ + "id", + "status" + ], + "type": "object" +}
- Changed
create_multi_channel_verification6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / client_metadata / additionalProperties / typeRemoved value: -"string" - changed
Input schema / properties / client_metadata / descriptionPrevious value: -"Custom key-value metadata"New value: +"Your own key-value data, stored with the request" - added
Input schema / properties / client_metadata / propertyNamesAdded value: +{ + "type": "string" +} - added
Input schema / properties / profile_idAdded value: +{ + "description": "Sub-account whose name and templates the request uses; omitted: the key's sub-account, else the primary", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channels": {}, + "client_metadata": {}, + "created_at": {}, + "expires_at": { + "description": "When every channel challenge expires" + }, + "external_user_id": {}, + "group_id": { + "description": "Verification group ID (vg_ prefix)" + }, + "identifier": {}, + "status": { + "description": "Current status of the verification" + }, + "type": {} + }, + "type": "object" +}
- Changed
create_profile6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / email_theme / descriptionPrevious value: -"Theme of this project's emails"New value: +"Theme of this sub-account's emails" - changed
Input schema / properties / support_email / descriptionPrevious value: -"Support email this project's messages show"New value: +"Support email this sub-account's messages show" - added
Input schema / properties / support_email / patternAdded value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" - removed
Input schema / properties / theme / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account as its owner sees it", + "properties": { + "avatar_url": { + "description": "A URL or a data URI; null once cleared", + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "description": "Theme of this sub-account's emails; null when unset (read as `dark`).", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "description": "The public id used in profile URLs", + "type": "string" + }, + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "description": "Support address shown in this sub-account's messages; null when unset.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "description": "Profile theme customization", + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "description": "Absent until a username is claimed", + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "description": "Always 'basic'; no levels are computed; removed in the next major.", + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
create_session13 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / callback_urlRemoved value: -{ - "description": "URL to redirect after verification", - "type": "string" -} - changed
Input schema / properties / channel / descriptionPrevious value: -"Verification channel"New value: +"How the person proves the number: telegram or whatsapp (the bot reads it from their account) or sms (they text a short code from it). No phone number is sent" - changed
Input schema / properties / channel / enumPrevious value: -[ - "sms", - "whatsapp", - "telegram" -]New value: +[ + "telegram", + "whatsapp", + "sms" +] - added
Input schema / properties / client_metadataAdded value: +{ + "additionalProperties": {}, + "description": "Your own key-value data, stored with the session", + "propertyNames": { + "type": "string" + }, + "type": "object" +} - added
Input schema / properties / contextAdded value: +{ + "properties": { + "action": { + "description": "Picks the bot's wording: log in, 2FA, account recovery, or plain verification (the default)", + "enum": [ + "login", + "2fa", + "verification", + "recovery" + ], + "type": "string" + } + }, + "type": "object" +} - removed
Input schema / properties / external_user_idRemoved value: -{ - "description": "Your application user ID", - "type": "string" -} - removed
Input schema / properties / metadataRemoved value: -{ - "additionalProperties": { - "type": "string" - }, - "description": "Custom key-value metadata", - "type": "object" -} - removed
Input schema / properties / phone_numberRemoved value: -{ - "description": "Phone number in E.164 format", - "type": "string" -} - added
Input schema / properties / profile_idAdded value: +{ + "description": "Sub-account whose name and templates the bot uses; omitted: the key's sub-account, else the primary", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - removed
Input schema / properties / template_idRemoved value: -{ - "description": "Custom template ID", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "channel", - "phone_number" -]New value: +[ + "channel" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "How the person proves the number: `telegram` or `whatsapp` (the bot reads the number from their account), or `sms` (they text a short code from the number to one of ours)." + }, + "deep_link": { + "description": "Opens the messenger (`https://t.me/…`, `https://wa.me/…`) or the messaging app (`sms:<number>?body=…`) with what the person sends" + }, + "expires_at": {}, + "id": { + "description": "Session id" + }, + "instructions": { + "description": "One line telling the person what to do" + }, + "qr_code": { + "description": "Base64-encoded PNG QR code for `deep_link`" + }, + "qr_text": { + "description": "UTF-8 text QR for `deep_link`, for terminal/agent rendering" + }, + "sms_code": { + "description": "The short code the person texts (`sms` only)" + }, + "sms_dids": { + "description": "Every number an `sms` session's code can be texted to, one per configured region (a region with no number is absent), each with its own QR code. `deep_link` uses the default region's number; the request comes from your server, so nothing in it says where the person is." + }, + "sms_message": { + "description": "The message to send, as pre-filled in the links (`sms` only)" + }, + "status": {} + }, + "type": "object" +}
- Changed
create_user_request9 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / action_context / additionalPropertiesRemoved value: -false - removed
Input schema / properties / assets / items / additionalPropertiesRemoved value: -false - changed
Input schema / properties / assets / items / properties / allowed_channels / items / enumPrevious value: -[ - "whatsapp", - "telegram", - "sms", - "email", - "dns", - "http", - "auto", - "github", - "google", - "facebook", - "x", - "linkedin", - "instagram", - "youtube", - "tiktok", - "ethereum", - "solana", - "bitcoin", - "coinbase", - "kraken", - "telegram_bot_token" -]New value: +[ + "whatsapp", + "telegram", + "sms", + "email", + "dns", + "http", + "auto", + "telegram_bot_token" +] - changed
Input schema / properties / assets / items / properties / channel / enumPrevious value: -[ - "whatsapp", - "telegram", - "sms", - "email", - "dns", - "http", - "auto", - "github", - "google", - "facebook", - "x", - "linkedin", - "instagram", - "youtube", - "tiktok", - "ethereum", - "solana", - "bitcoin", - "coinbase", - "kraken", - "telegram_bot_token" -]New value: +[ + "whatsapp", + "telegram", + "sms", + "email", + "dns", + "http", + "auto", + "telegram_bot_token" +] - changed
Input schema / properties / assets / items / properties / type / enumPrevious value: -[ - "phone", - "email", - "domain", - "social", - "wallet", - "telegram_bot" -]New value: +[ + "phone", + "email", + "domain", + "telegram_bot" +] - removed
Input schema / properties / callback_url / formatRemoved value: -"uri" - removed
Input schema / properties / redirect_url / formatRemoved value: -"uri" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "action_context": { + "description": "The action the person is asked to authorize; null when the request carries none" + }, + "action_type": { + "description": "Type of action for verification request or authorization" + }, + "assets": {}, + "callback_url": { + "description": "The webhook URL set on the request, if any" + }, + "completed_at": {}, + "computed_state": { + "description": "Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces." + }, + "created_at": {}, + "expires_at": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "partial_ok": {}, + "progress": {}, + "redirect_url": {}, + "reference_id": {}, + "status": { + "description": "Status of a verification request" + }, + "updated_at": {}, + "validity_requirement": { + "description": "Required proof freshness as set on the request (e.g. \"7d\"); null when none was set" + }, + "verification_url": { + "description": "URL for the verification flow" + } + }, + "type": "object" +}
- Changed
create_verification5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / client_metadata / propertyNamesAdded value: +{ + "type": "string" +} - added
Input schema / properties / dns_provider / propertyNamesAdded value: +{ + "type": "string" +} - added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (24 hex characters) this is for; omitted, the key's own sub-account, else the primary. Its branding and templates are used for every message.", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "attempts": {}, + "challenge": { + "description": "Challenge details for verification" + }, + "channel": { + "description": "Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken." + }, + "created_at": {}, + "external_user_id": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "identifier": { + "description": "The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it" + }, + "max_attempts": {}, + "proof": { + "description": "Proof token after successful verification" + }, + "status": { + "description": "Current status of the verification" + }, + "type": { + "description": "Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account." + }, + "updated_at": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
create_verification_request11 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / action_context / additionalPropertiesRemoved value: -false - removed
Input schema / properties / assets / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / assets / items / properties / allowed_channels / items / $refRemoved value: -"#/properties/assets/items/properties/channel" - added
Input schema / properties / assets / items / properties / allowed_channels / items / enumAdded value: +[ + "whatsapp", + "telegram", + "sms", + "email", + "dns", + "http", + "auto", + "github", + "google", + "facebook", + "x", + "linkedin", + "instagram", + "youtube", + "tiktok", + "ethereum", + "solana", + "bitcoin", + "coinbase", + "kraken", + "telegram_bot_token" +] - added
Input schema / properties / assets / items / properties / allowed_channels / items / typeAdded value: +"string" - added
Input schema / properties / expires_in / maximumAdded value: +9007199254740991 - added
Input schema / properties / proof_expiry_days / maximumAdded value: +9007199254740991 - added
Input schema / properties / proof_expiry_days / minimumAdded value: +-9007199254740991 - added
Input schema / properties / validity_requirementAdded value: +{ + "description": "How fresh an existing proof must be to count, as <n>h, <n>d, <n>w or <n>m (e.g. \"7d\")", + "pattern": "^\\d+[hdwm]$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "action_context": { + "description": "The action the person is asked to authorize; null when the request carries none" + }, + "action_type": { + "description": "Type of action for verification request or authorization" + }, + "assets": {}, + "callback_url": { + "description": "The webhook URL set on the request, if any" + }, + "completed_at": {}, + "computed_state": { + "description": "Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces." + }, + "created_at": {}, + "expires_at": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "partial_ok": {}, + "progress": {}, + "redirect_url": {}, + "reference_id": {}, + "status": { + "description": "Status of a verification request" + }, + "updated_at": {}, + "validity_requirement": { + "description": "Required proof freshness as set on the request (e.g. \"7d\"); null when none was set" + }, + "verification_url": { + "description": "URL for the verification flow" + } + }, + "type": "object" +}
- Added
create_webhook_endpoint - Changed
delete_circle2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": {}, + "type": "object" +}
- Changed
delete_dns_credential2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
delete_domain2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "carriers": { + "description": "Where the revoked delegations are still published (the `_mcp.<domain>` pointer, a delegate card) — bounded to a few delegations and a few seconds." + }, + "delegations_revoked": {}, + "domain": {}, + "external": {}, + "notice": {}, + "proofs_revoked": {}, + "success": { + "description": "Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major." + } + }, + "type": "object" +}
- Changed
delete_domain_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "deleted": { + "const": true, + "description": "The domain verification was deleted", + "type": "boolean" + }, + "id": { + "description": "The id of the deleted domain verification", + "type": "string" + } + }, + "required": [ + "deleted", + "id" + ], + "type": "object" +}
- Changed
delete_hitl2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "HITL configuration with messaging channels and timeout", + "properties": { + "channels": { + "items": { + "oneOf": [ + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "chat_id": { + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "bsuid": { + "type": "string" + }, + "phone_number": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } + ] + }, + "type": "array" + }, + "circle_id": { + "description": "Backing Circle for a circle-backed Approvals config (null for channel-list configs)", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "keypair": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "has_backup_wrapper": { + "type": "boolean" + }, + "has_encrypted_private_key": { + "type": "boolean" + }, + "has_wrapped_dek": { + "type": "boolean" + }, + "kid": { + "type": "string" + } + }, + "required": [ + "kid", + "has_encrypted_private_key", + "has_wrapped_dek", + "has_backup_wrapper" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Encryption keypair metadata (null if not configured)" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Status of a HITL configuration", + "type": "string" + }, + "timeout_seconds": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "description": "Owner user ID (useful for SDK encryption AAD)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "channels", + "timeout_seconds", + "status", + "keypair", + "environment", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
delete_hitl_keys2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "message": {} + }, + "type": "object" +}
- Changed
delete_profile2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "api_keys_revoked": {}, + "authorizations_revoked": {}, + "circles_detached": {}, + "confirmations_denied": {}, + "domains_detached": {}, + "hitl_archived": {}, + "hitl_detached": {}, + "message": {}, + "new_primary": { + "description": "Named when the deleted sub-account is (or was) the primary: the OLDEST remaining sub-account takes over, and messages sent without choosing a sub-account carry its name." + }, + "project": {}, + "requests_cancelled": {}, + "requests_detached": {}, + "success": { + "description": "Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major." + }, + "templates_deleted": {}, + "username_retired": { + "description": "The username is retired for good — it can never be claimed again, by anyone." + }, + "verifications_detached": {}, + "was_primary": {} + }, + "type": "object" +}
- Changed
delete_template3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key"New value: +"The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Added
delete_webhook_endpoint - Changed
export_authorizations2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": {}, + "total": {} + }, + "type": "object" +}
- Changed
export_data2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "counts": { + "description": "Rows per section of the file" + }, + "download_path": { + "description": "Path of the download route while `ready`, else null" + }, + "downloaded_at": { + "description": "The first download, if any" + }, + "error": { + "description": "`too_large` — more than one download can carry (no partial file is ever produced; contact support); `internal` — a failure on our side (start a new export at once, the daily limit was given back)" + }, + "expires_at": { + "description": "The export and its file are deleted at this time — 7 days after the request" + }, + "id": {}, + "latest": {}, + "ready_at": {}, + "receipts": { + "description": "Receipts of the account's downloads, newest first (the latest 20)" + }, + "requested_at": {}, + "size_bytes": { + "description": "Size of the compressed file as stored" + }, + "status": { + "description": "`preparing` while the job runs; `ready` once the file can be downloaded; `failed` with `error`" + } + }, + "type": "object" +}
- Changed
extend_request3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / extends_by_hoursAdded value: +{ + "description": "Hours from now until the request expires, 1–720 (default: 168, i.e. 7 days). An expired request is reactivated.", + "maximum": 720, + "minimum": 1, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The request's new expiry", + "properties": { + "expires_at": { + "type": "string" + }, + "message": { + "description": "`Verification request extended`, or `Verification request reactivated and extended` for a request that had expired (its `status` is then `pending` or `partial` again)", + "type": "string" + }, + "status": { + "description": "Status of a verification request", + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "expires_at", + "status" + ], + "type": "object" +}
- Changed
get_2fa_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A 2FA session's state; the grant fields are present once `status` is `verified`", + "properties": { + "action_type": { + "description": "The action the session was started for: one of `TwoFAActionType` for sessions started through this API; admin-console sessions carry internal values.", + "type": "string" + }, + "grant_expires_at": { + "description": "When the grant this step-up stored stops being accepted", + "type": "string" + }, + "grant_single_use": { + "description": "Whether the grant is spent by the first act it allows", + "type": "boolean" + }, + "session_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "session_id", + "status", + "action_type" + ], + "type": "object" +}
- Changed
get_add_email_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "An email-add session's state", + "properties": { + "channel": { + "type": "string" + }, + "email": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "description": "Present once `status` is `verified`", + "type": "string" + } + }, + "required": [ + "session_id", + "email", + "channel", + "status" + ], + "type": "object" +}
- Changed
get_add_phone_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A phone-add session's state", + "properties": { + "channel": { + "type": "string" + }, + "phone_number": { + "description": "The number the person proved; absent until they have", + "type": "string" + }, + "session_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "description": "Present once `status` is `verified`", + "type": "string" + } + }, + "required": [ + "session_id", + "channel", + "status" + ], + "type": "object" +}
- Changed
get_api_key_usage2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Per-API-key usage: verification counts by type/channel/status + per-collection totals (requests, confirmations, authorizations) + attribution metadata. The counts cover the key and every key it replaced (`api_key.replaced_key_ids`). Counts only — no recipient identifiers (SEC-001). Data is returned for revoked keys (audit).", + "properties": { + "api_key": { + "additionalProperties": {}, + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "expires_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "key_prefix": { + "type": "string" + }, + "last_used_at": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "replaced_key_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "revoked_at": { + "type": [ + "string", + "null" + ] + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "key_prefix", + "environment", + "scopes", + "last_used_at", + "expires_at", + "revoked_at", + "created_at" + ], + "type": "object" + }, + "attributed_fraction": { + "description": "Fraction of the user verifications linked to any API key in scope (null when there are none)", + "type": [ + "number", + "null" + ] + }, + "attribution_cutoff_at": { + "description": "UTC-day-floored date attribution began for this user (earliest key-linked verification), or null", + "type": [ + "string", + "null" + ] + }, + "authorizations": { + "additionalProperties": {}, + "properties": { + "by_status": { + "additionalProperties": { + "type": "number" + }, + "properties": {}, + "type": "object" + }, + "total": { + "type": "number" + } + }, + "required": [ + "total", + "by_status" + ], + "type": "object" + }, + "confirmations": { + "additionalProperties": {}, + "properties": { + "by_status": { + "additionalProperties": { + "type": "number" + }, + "properties": {}, + "type": "object" + }, + "total": { + "type": "number" + } + }, + "required": [ + "total", + "by_status" + ], + "type": "object" + }, + "verification_requests": { + "additionalProperties": {}, + "properties": { + "by_status": { + "additionalProperties": { + "type": "number" + }, + "properties": {}, + "type": "object" + }, + "total": { + "type": "number" + } + }, + "required": [ + "total", + "by_status" + ], + "type": "object" + }, + "verifications": { + "additionalProperties": {}, + "properties": { + "by_channel": { + "additionalProperties": { + "type": "number" + }, + "properties": {}, + "type": "object" + }, + "by_status": { + "additionalProperties": { + "type": "number" + }, + "properties": {}, + "type": "object" + }, + "by_type": { + "additionalProperties": { + "type": "number" + }, + "properties": {}, + "type": "object" + }, + "total": { + "type": "number" + } + }, + "required": [ + "total", + "by_type", + "by_channel", + "by_status" + ], + "type": "object" + } + }, + "required": [ + "api_key", + "verifications", + "verification_requests", + "confirmations", + "authorizations", + "attribution_cutoff_at", + "attributed_fraction" + ], + "type": "object" +}
- Changed
get_asset2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "User verified asset", + "properties": { + "channel": { + "description": "How the asset was verified: a verification channel, or `otp` / `magic_link` for an email address confirmed from the dashboard", + "type": "string" + }, + "created_at": { + "type": "string" + }, + "has_proof": { + "description": "Whether a proof token is stored for this asset. Sent by the point read (`GET /me/assets/{id}`) only.", + "type": "boolean" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "identifier": { + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "description": "Channel-specific details recorded at verification", + "properties": {}, + "type": "object" + }, + "proof_expires_at": { + "description": "When the proof backing this asset expires", + "type": "string" + }, + "proof_id": { + "description": "Public handle of the proof backing this asset (`ph_ctl_<32 hex>`), or null when the asset predates the proof registry. This is the `control_proof` value `POST /api/v1/delegations` takes.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. Only an `active` proof can anchor a delegation.", + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "description": "The stored signed proof token. Returned by the point read (`GET /me/assets/{id}`) to a JWT owner session ONLY — an API-key caller and the list response carry `has_proof` alone.", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Status of a verified asset", + "type": "string" + }, + "type": { + "description": "Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account.", + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "channel", + "identifier", + "status", + "proof_expires_at", + "created_at" + ], + "type": "object" +}
- Changed
get_authorization2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Authorization granting permission to send confirmations via a specific channel", + "properties": { + "authorized_at": { + "type": "string" + }, + "bsuid": { + "description": "WhatsApp Business-Scoped User ID", + "type": [ + "string", + "null" + ] + }, + "business_name": { + "type": "string" + }, + "channel": { + "description": "Channel authorized for sending confirmations", + "type": "string" + }, + "circle_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "confirmations_sent": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "denied_at": { + "description": "When the recipient refused — the mirror of `authorized_at` for a `denied` row (a challenger cancellation stamps it too). Absent unless the authorization was denied; before it existed such a row carried no decision time at all, only `updated_at`.", + "type": "string" + }, + "enrolled": { + "description": "Whether the approver has enrolled an encryption key. A confirmation can be sealed to an approver only once this is true; consent alone (`status: active`) is not enough.", + "type": "boolean" + }, + "expires_at": { + "type": "string" + }, + "hitl_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "label": { + "description": "Owner-assigned human label for this approver (F22); null when unset. Surfaces lead with it, falling back to the masked recipient.", + "type": [ + "string", + "null" + ] + }, + "last_used_at": { + "type": "string" + }, + "phone": { + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "description": "Signed proof of the recipient's decision, minted when they approved or refused, for both scopes. Absent while no decision has been made.", + "type": "string" + }, + "recipient": { + "description": "Channel-specific recipient identifier (chat_id for Telegram, phone or BSUID for WhatsApp)", + "type": [ + "string", + "null" + ] + }, + "recipient_display_name": { + "description": "The approver's own messenger name (\"First Last @username\"), captured when they approved over Telegram; null when none was captured. Chosen by the approver, not verified.", + "type": [ + "string", + "null" + ] + }, + "revocation_reason": { + "type": "string" + }, + "revoked_at": { + "type": "string" + }, + "scope": { + "description": "Scope of the authorization. `identity_challenge` is the Proof of Me scope.", + "type": "string" + }, + "status": { + "description": "Status of an authorization", + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_id": { + "description": "MongoDB ObjectId", + "type": "string" + } + }, + "required": [ + "id", + "status", + "channel", + "scope", + "business_name", + "recipient_display_name", + "enrolled", + "expires_at", + "confirmations_sent", + "created_at", + "updated_at" + ], + "type": "object" +}
- Added
get_balance - Changed
get_circle2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A Circle — a named group of trusted contacts", + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "member_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "members": { + "items": { + "additionalProperties": {}, + "properties": { + "enrolled_at": { + "type": [ + "string", + "null" + ] + }, + "enrolled_phone_hint": { + "type": [ + "string", + "null" + ] + }, + "has_telegram": { + "type": "boolean" + }, + "has_whatsapp": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "last_verified_at": { + "type": [ + "string", + "null" + ] + }, + "mesh_opt_out": { + "type": "boolean" + }, + "mesh_opted_in": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "status", + "has_telegram", + "has_whatsapp", + "mesh_opted_in", + "mesh_opt_out", + "enrolled_phone_hint", + "enrolled_at", + "last_verified_at" + ], + "type": "object" + }, + "type": "array" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "owner_name": { + "description": "How this Circle's members know its owner; null when unset", + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "proof_me_enabled": { + "type": "boolean" + }, + "status": { + "description": "Lifecycle state of a Circle (archived = soft-retired)", + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "name", + "owner_name", + "profile_id", + "environment", + "proof_me_enabled", + "status", + "member_count", + "members", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
get_confirmation2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A HITL confirmation request", + "properties": { + "created_at": { + "type": "string" + }, + "hitl_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "message": { + "description": "The stored ciphertext envelope, echoed back verbatim. The server never sees the plaintext, so this is never the human sentence — the approver decrypts it in their browser.", + "type": "string" + }, + "proof_token": { + "description": "Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`)", + "type": [ + "string", + "null" + ] + }, + "resends": { + "description": "Every \"Send again\" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it.", + "items": { + "additionalProperties": {}, + "properties": { + "actor": { + "additionalProperties": {}, + "properties": { + "api_key_id": { + "type": [ + "string", + "null" + ] + }, + "kind": { + "type": "string" + } + }, + "required": [ + "kind", + "api_key_id" + ], + "type": "object" + }, + "at": { + "type": "string" + }, + "channels": { + "items": { + "additionalProperties": {}, + "properties": { + "recipient": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "recipient" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "at", + "actor", + "channels" + ], + "type": "object" + }, + "type": "array" + }, + "resolved_at": { + "type": [ + "string", + "null" + ] + }, + "response": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "action": { + "type": "string" + }, + "at": { + "type": "string" + }, + "authorization_id": { + "type": [ + "string", + "null" + ] + }, + "channel": { + "type": [ + "string", + "null" + ] + }, + "decided_by": { + "type": [ + "string", + "null" + ] + }, + "kid": { + "type": [ + "string", + "null" + ] + }, + "public_key": { + "type": [ + "string", + "null" + ] + }, + "signature": { + "type": [ + "string", + "null" + ] + }, + "signed_input": { + "type": [ + "string", + "null" + ] + }, + "text": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "action", + "at" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "The decision and its evidence (null while pending)" + }, + "status": { + "description": "Status of a confirmation request. A confirmation that times out is `denied`, with `response.channel` `system` and `response.text` `timeout`.", + "type": "string" + }, + "timeout_at": { + "description": "When this confirmation will time out", + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "hitl_id", + "message", + "status", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
get_confirmation_approval_link2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Regenerated approval link for a pending confirmation", + "properties": { + "approval_url": { + "type": "string" + } + }, + "required": [ + "approval_url" + ], + "type": "object" +}
- Changed
get_current_user1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "created_at": {}, + "emails": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "phone_numbers": {} + }, + "type": "object" +}
- Changed
get_default_templates1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The platform default templates", + "properties": { + "defaults": { + "additionalProperties": {}, + "description": "The platform default of every channel and message type some send renders, keyed message type → channel. A pair nothing sends is left out.", + "properties": { + "2fa_request": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "2fa_success": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "account_deletion_request": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "account_deletion_success": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "confirmation_approved": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "confirmation_denied": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "confirmation_request": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "login_request": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "login_success": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "verification_expired": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "verification_request": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + }, + "verification_success": { + "additionalProperties": {}, + "properties": { + "email": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "sms": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "telegram": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "whatsapp": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "subject": { + "type": "string" + } + }, + "required": [ + "body" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "defaults" + ], + "type": "object" +}
- Changed
get_delegation2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "control_proof": { + "description": "The control proof handle this delegation points down to" + }, + "created_at": {}, + "delegate": { + "description": "Typed delegate identifier" + }, + "delegation_id": { + "description": "Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint" + }, + "effective_status": { + "description": "DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects" + }, + "environment": {}, + "expires_at": { + "description": "Never later than the control proof's own expiry at issuance (effective expiry is min of the two)" + }, + "id": { + "description": "MongoDB ObjectId" + }, + "is_valid": { + "description": "True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above" + }, + "issued_at": {}, + "principal": { + "description": "The proven domain that authorized the delegate — derived from the control proof, never client input" + }, + "revoked_at": {}, + "revoked_reason": {}, + "scope": { + "description": "Deprecated. Delegation schema 2.0 carries no scope; this array stays for the SDKs released before it: the scope a delegation issued before schema 2.0 was stored with, otherwise empty. Removed in the next major version." + }, + "status": { + "description": "The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on" + }, + "token": { + "description": "The signed delegation JWT — the PUBLISHABLE artifact (publish it in your MCP server card under `_meta` → `holdings.proof/delegation`). Same key, algorithm and JWKS as proof tokens" + } + }, + "type": "object" +}
- Added
get_delegation_token - Changed
get_dns_providers1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The DNS providers credentials can be saved for", + "properties": { + "count": { + "description": "How many providers are supported. A supported provider with no metadata on record is counted here but not listed in `providers`.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "providers": { + "additionalProperties": { + "additionalProperties": {}, + "properties": { + "apiDocUrl": { + "type": "string" + }, + "capabilities": { + "additionalProperties": {}, + "properties": { + "canCreateTxt": { + "type": "boolean" + }, + "hasOAuth": { + "type": "boolean" + }, + "isRegistrar": { + "type": "boolean" + } + }, + "required": [ + "hasOAuth", + "isRegistrar", + "canCreateTxt" + ], + "type": "object" + }, + "name": { + "type": "string" + }, + "optionalCredentials": { + "items": { + "type": "string" + }, + "type": "array" + }, + "requiredCredentials": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "requiredCredentials", + "optionalCredentials", + "capabilities" + ], + "type": "object" + }, + "description": "Each supported provider with metadata on record, keyed by provider id", + "properties": {}, + "type": "object" + } + }, + "required": [ + "providers", + "count" + ], + "type": "object" +}
- Changed
get_domain2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A domain with the steps to verify it", + "properties": { + "data": { + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "type": "string" + }, + "dns_mismatch_warning": { + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "type": "boolean" + }, + "oauth_url": { + "type": "string" + }, + "profile_id": { + "type": "string" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "provider_credential_name": { + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "type": "string" + }, + "verification_subtype": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "instructions": { + "additionalProperties": {}, + "description": "How to show control of the domain by the method it is set to", + "properties": { + "dns_record": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value" + ], + "type": "object" + }, + "http_file": { + "additionalProperties": {}, + "properties": { + "content": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "path", + "content" + ], + "type": "object" + }, + "method": { + "type": "string" + }, + "steps": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "method", + "steps", + "http_file" + ], + "type": "object" + } + }, + "required": [ + "data", + "instructions" + ], + "type": "object" +}
- Changed
get_hitl2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "HITL configuration with messaging channels and timeout", + "properties": { + "channels": { + "items": { + "oneOf": [ + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "chat_id": { + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "bsuid": { + "type": "string" + }, + "phone_number": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } + ] + }, + "type": "array" + }, + "circle_id": { + "description": "Backing Circle for a circle-backed Approvals config (null for channel-list configs)", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "keypair": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "has_backup_wrapper": { + "type": "boolean" + }, + "has_encrypted_private_key": { + "type": "boolean" + }, + "has_wrapped_dek": { + "type": "boolean" + }, + "kid": { + "type": "string" + } + }, + "required": [ + "kid", + "has_encrypted_private_key", + "has_wrapped_dek", + "has_backup_wrapper" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Encryption keypair metadata (null if not configured)" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Status of a HITL configuration", + "type": "string" + }, + "timeout_seconds": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "description": "Owner user ID (useful for SDK encryption AAD)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "channels", + "timeout_seconds", + "status", + "keypair", + "environment", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
get_hitl_keys2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A HITL config's keypair. A caller with `hitl:read` (or a dashboard session) gets every field; a key holding `confirmations:create` without `hitl:read` gets `public_key` and `kid` only.", + "properties": { + "backup_dek_iv": { + "type": [ + "string", + "null" + ] + }, + "backup_dek_tag": { + "type": [ + "string", + "null" + ] + }, + "backup_wrapped_dek": { + "description": "The same data key wrapped under the recovery key; null until recovery is set up", + "type": [ + "string", + "null" + ] + }, + "dek_iv": { + "type": [ + "string", + "null" + ] + }, + "dek_tag": { + "type": [ + "string", + "null" + ] + }, + "encrypted_private_key": { + "description": "The private key as stored, wrapped client-side. Absent for a key holding `confirmations:create` without `hitl:read`.", + "type": "string" + }, + "kdf_salt": { + "description": "The salt the wrapping key is derived with. Absent for a key holding `confirmations:create` without `hitl:read`.", + "type": "string" + }, + "kid": { + "description": "The key id: lowercase hex SHA-256 of the public key's SPKI DER", + "type": "string" + }, + "public_key": { + "description": "The RSA public key (SPKI PEM) messages are sealed to. Null means the stored key material could not be read: a degraded state to report, not \"no key yet\" (a config with no keypair answers 404 `no_keypair`).", + "type": [ + "string", + "null" + ] + }, + "wrapped_dek": { + "description": "The per-config data key wrapped under the master key; null for a keypair stored before it existed. Absent for a requester key, as are the five fields below.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "public_key", + "kid" + ], + "type": "object" +}
- Changed
get_identity_challenge2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "An identity challenge (Proof of Me)", + "properties": { + "channel": { + "description": "Channel the CONFIRM was dispatched on (GET)", + "type": "string" + }, + "circle_id": { + "description": "The Circle the check belongs to (GET)", + "type": [ + "string", + "null" + ] + }, + "confirm_channel": { + "description": "Channel the CONFIRM was dispatched on (POST)", + "type": "string" + }, + "created_at": { + "description": "ISO 8601 timestamp", + "type": "string" + }, + "expires_at": { + "description": "ISO 8601 timestamp", + "type": "string" + }, + "id": { + "type": "string" + }, + "is_drill": { + "description": "True for a drill (scheduled, or started from the dashboard) rather than a real check (GET)", + "type": "boolean" + }, + "proof_id": { + "description": "Public handle of the decision's proof — what `POST /proofs/{proof_id}/revoke` takes. Null until a decision minted one (GET).", + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "description": "Signed proof token, present once the person being checked decided", + "type": [ + "string", + "null" + ] + }, + "resolved_at": { + "description": "ISO 8601 timestamp of the decision — the CONFIRM, the DENY, the cancellation or the delivery failure — or null while the check is unanswered and after a timeout.", + "type": [ + "string", + "null" + ] + }, + "single_channel_warning": { + "description": "True when the account holder has only one channel, so the CONFIRM ran on the same channel as the suspicious contact (degraded)", + "type": "boolean" + }, + "status": { + "description": "The one status every read reports. `pending` — waiting for the person being checked; `confirmed` — they confirmed; `denied` — they denied; `cancelled` — whoever started the check withdrew it; `failed` — the check could not be delivered; `expired` — nobody answered in time; `revoked` / `suspended` — the confirmation's proof was revoked or suspended (`POST /proofs/{proof_id}/revoke` or `/suspend`; revoking a denial's proof leaves it `denied`), or — `revoked` only — the member being checked was removed from the Circle while the check was still pending, which leaves `proof_id` null. Removing a member is not guaranteed to revoke a confirmation they already gave; revoke that one by its `proof_id`. A proof that merely reached its own expiry still reads `confirmed`; whether its token is still valid is `POST /proofs/validate`'s answer.", + "type": "string" + } + }, + "required": [ + "id", + "status" + ], + "type": "object" +}
- Changed
get_multi_channel_verification_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channels": { + "description": "Per-channel statuses without per-channel error detail" + }, + "group_id": {}, + "proof": {}, + "status": { + "description": "Group-level status: verified as soon as any channel completes" + }, + "winning_channel": { + "description": "Channel that completed the verification (null while pending)" + } + }, + "type": "object" +}
- Changed
get_my_profile1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account as its owner sees it", + "properties": { + "avatar_url": { + "description": "A URL or a data URI; null once cleared", + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "description": "Theme of this sub-account's emails; null when unset (read as `dark`).", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "description": "The public id used in profile URLs", + "type": "string" + }, + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "description": "Support address shown in this sub-account's messages; null when unset.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "description": "Profile theme customization", + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "description": "Absent until a username is claimed", + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "description": "Always 'basic'; no levels are computed; removed in the next major.", + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
get_platform_summary3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / profile_idAdded value: +{ + "description": "Scope the metrics and key counts to one sub-account (24 hex characters); the quota stays account-wide", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "active_api_keys": {}, + "as_of": { + "description": "When the snapshot was computed (ISO 8601)" + }, + "cache_age_seconds": { + "description": "Always 0 — computed live" + }, + "channels_with_zero_completions": {}, + "hitl_channels": { + "description": "Present only with hitl:read scope (JWT always)" + }, + "next_action": { + "description": "Most-pressing account action; null when healthy" + }, + "quota": {}, + "request_health": {}, + "top_channels": {} + }, + "type": "object" +}
- Changed
get_profile2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account as its owner sees it", + "properties": { + "avatar_url": { + "description": "A URL or a data URI; null once cleared", + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "description": "Theme of this sub-account's emails; null when unset (read as `dark`).", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "description": "The public id used in profile URLs", + "type": "string" + }, + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "description": "Support address shown in this sub-account's messages; null when unset.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "description": "Profile theme customization", + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "description": "Absent until a username is claimed", + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "description": "Always 'basic'; no levels are computed; removed in the next major.", + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
get_profile_assets2 fields changed- added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account whose shown proofs set each asset's is_public flag (24 hex characters); omitted, the primary", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "assets": { + "items": { + "additionalProperties": {}, + "properties": { + "channel": { + "type": "string" + }, + "id": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "is_public": { + "type": "boolean" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "identifier", + "channel", + "is_public" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "assets" + ], + "type": "object" +}
- Changed
get_proof_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "expires_at": {}, + "is_expired": {}, + "is_revoked": {}, + "is_valid": {}, + "proof_id": { + "description": "Public proof handle (`ph_ctl_<32 hex>`), or a verification id for a legacy proof" + }, + "revoked_at": {}, + "revoked_reason": {}, + "status": { + "description": "Current status of the proof — `active` is a live proof, `suspended` the reversible pause" + }, + "suspended_at": { + "description": "When the current suspension began (null unless status is `suspended`)" + } + }, + "type": "object" +}
- Added
get_proof_token - Changed
get_request_by_reference2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "action_context": { + "description": "The action the person is asked to authorize; null when the request carries none" + }, + "action_type": { + "description": "Type of action for verification request or authorization" + }, + "assets": {}, + "callback_url": { + "description": "The webhook URL set on the request, if any" + }, + "completed_at": {}, + "computed_state": { + "description": "Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces." + }, + "created_at": {}, + "expires_at": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "partial_ok": {}, + "progress": {}, + "redirect_url": {}, + "reference_id": {}, + "status": { + "description": "Status of a verification request" + }, + "updated_at": {}, + "validity_requirement": { + "description": "Required proof freshness as set on the request (e.g. \"7d\"); null when none was set" + }, + "verification_url": { + "description": "URL for the verification flow" + } + }, + "type": "object" +}
- Changed
get_request_proofs2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "proofs": {} + }, + "type": "object" +}
- Changed
get_self_api_key1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "An API key's redacted metadata, as the calling key reads itself (`GET /me/api-key`). Never carries the key value.", + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "expires_at": { + "description": "When the key stops authenticating; null means it never expires. Enforced at authentication — an expired key is rejected exactly like an unknown one.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "key_prefix": { + "type": "string" + }, + "last_used_at": { + "description": "When the key last authenticated a request; null if never", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "profile_id": { + "description": "Sub-account (PublicProfile) the key is bound to; null for unbound keys.", + "type": [ + "string", + "null" + ] + }, + "replaced_key_ids": { + "description": "Ids of the keys this key replaced, newest first: the earlier keys of the same integration, replaced when the key was regenerated (`POST /api/v1/me/api-keys/{id}/regenerate`) or renewed by an MCP sign-in refresh. Requests and usage of those keys count as this key's. Empty when it replaced none. Recorded from the release of key history on; a key replaced before it is not linked.", + "items": { + "type": "string" + }, + "type": "array" + }, + "revoked_at": { + "description": "When the key was revoked; null while it is live", + "type": [ + "string", + "null" + ] + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "key_prefix", + "environment", + "scopes", + "created_at" + ], + "type": "object" +}
- Changed
get_session2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "How the person proves the number: `telegram` or `whatsapp` (the bot reads the number from their account), or `sms` (they text a short code from the number to one of ours)." + }, + "created_at": {}, + "id": { + "description": "Session id" + }, + "phone_number": { + "description": "The proven number (once `verified`)" + }, + "proof": { + "description": "Proof token after successful verification" + }, + "status": {}, + "verification_id": { + "description": "The verification record created on completion (once `verified`)" + }, + "verified_at": { + "description": "Once `verified`" + } + }, + "type": "object" +}
- Changed
get_settings1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "hitl": { + "description": "Approval-setup settings." + }, + "proof_expiry_days": { + "description": "Default lifetime in days of newly issued verification proofs, or null when the account has never set one. Confirmation-decision proofs do not use it." + }, + "webhook": { + "description": "Outbound webhook configuration — DEPRECATED (#421). An account switched over to webhook endpoints sees its account-wide (`legacy`) endpoint here: `url` is null while that endpoint is disabled, a `url` write updates or creates it, `url: null` disables it (its secret is kept), and `rotate_secret` rotates its secret. An account not yet switched over sees its settings fields, as before. Omitted for an API key bound to one sub-account." + } + }, + "type": "object" +}
- Changed
get_subscription1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The account's subscription", + "properties": { + "cancel_at_period_end": { + "description": "Whether the subscription ends at the end of the current period; false without a subscription.", + "type": "boolean" + }, + "current_period_end": { + "description": "End of the current billing period; null without a subscription.", + "type": [ + "string", + "null" + ] + }, + "current_period_start": { + "description": "Start of the current billing period; null without a subscription.", + "type": [ + "string", + "null" + ] + }, + "plan": { + "description": "Plan to check out. `free` adds a card for pay as you go (the metered price past the included proofs); it is offered once billing is live.", + "type": "string" + }, + "scheduled_change_at": { + "description": "When the scheduled downgrade takes effect (the end of the paid period); null when nothing is scheduled.", + "type": [ + "string", + "null" + ] + }, + "scheduled_plan": { + "description": "The plan a scheduled downgrade moves the account to at `scheduled_change_at`; null when nothing is scheduled. Absent from an API that predates plan changes.", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Stripe's status for the subscription, whatever it is (the caller decides what counts as subscribed); null when the account has no subscription.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "plan", + "status", + "current_period_start", + "current_period_end", + "cancel_at_period_end" + ], + "type": "object" +}
- Changed
get_template3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key"New value: +"The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "is_custom": {}, + "profile_id": { + "description": "The sub-account resolved for this request; null for an account with no sub-account yet." + }, + "scope": { + "description": "`project` — the sub-account's own template; `default` — the platform default it falls back to." + }, + "template": { + "description": "Message template" + } + }, + "type": "object" +}
- Changed
get_usage2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Usage for the current billing period, with the months asked for", + "properties": { + "balance": { + "additionalProperties": {}, + "description": "The prepaid balance as `GET /me/billing/balance` reports it, without `billing_enabled` (the usage read carries that itself)", + "properties": { + "auto_top_up": { + "additionalProperties": {}, + "properties": { + "amount": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "enabled": { + "type": "boolean" + }, + "has_payment_method": { + "type": "boolean" + } + }, + "required": [ + "enabled", + "amount", + "has_payment_method" + ], + "type": "object" + }, + "balance": { + "additionalProperties": {}, + "properties": { + "amount": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "currency": { + "type": "string" + }, + "mills": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "amount", + "currency", + "mills" + ], + "type": "object" + }, + "low_balance_threshold": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "top_up_amounts": { + "items": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "balance", + "low_balance_threshold", + "top_up_amounts", + "auto_top_up" + ], + "type": "object" + }, + "billing_enabled": { + "type": "boolean" + }, + "card_on_file": { + "type": "boolean" + }, + "channels_with_zero_completions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "current_period": { + "description": "The current month, `YYYY-MM`", + "type": "string" + }, + "current_usage": { + "description": "Verifications, confirmations, authorizations and delegations this month, counted from the requested months' records: 0 when `period` names another month, since the current month's record is then not among them", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "days_remaining": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "hard_limit": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "is_on_track": { + "description": "null when fewer than 5 days have passed or usage is 0", + "type": [ + "boolean", + "null" + ] + }, + "limit": { + "description": "The plan's included verifications per month", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "percentage": { + "description": "`current_usage` as a percentage of `limit`, rounded", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "periods": { + "description": "The months asked for that have a record, newest first", + "items": { + "additionalProperties": {}, + "properties": { + "by_channel": { + "additionalProperties": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "properties": {}, + "type": "object" + }, + "by_hitl_channel": { + "additionalProperties": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "properties": {}, + "type": "object" + }, + "by_type": { + "additionalProperties": {}, + "properties": { + "domain": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "phone": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "social": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "telegram_bot": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "wallet": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "phone", + "email", + "domain", + "social", + "wallet", + "telegram_bot" + ], + "type": "object" + }, + "period": { + "type": "string" + }, + "total_authorizations": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_confirmations": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_delegations": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_verifications": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "period", + "total_verifications", + "total_confirmations", + "total_authorizations", + "total_delegations", + "by_type", + "by_channel", + "by_hitl_channel" + ], + "type": "object" + }, + "type": "array" + }, + "plan": { + "type": "string" + }, + "projected_eom_usage": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "projection_unreliable": { + "description": "true when the projection exceeds the limit three times over", + "type": "boolean" + }, + "top_channels": { + "items": { + "additionalProperties": {}, + "properties": { + "channel": { + "type": "string" + }, + "completion_rate": { + "type": "number" + }, + "count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "channel", + "count", + "completion_rate" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "plan", + "limit", + "billing_enabled", + "card_on_file", + "hard_limit", + "balance", + "current_period", + "current_usage", + "percentage", + "days_remaining", + "projected_eom_usage", + "is_on_track", + "projection_unreliable", + "top_channels", + "channels_with_zero_completions", + "periods" + ], + "type": "object" +}
- Changed
get_user_domain_verification_status2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A self-service domain verification session's state", + "properties": { + "challenge": { + "additionalProperties": {}, + "description": "What is still to be published, while the session is not verified (no `instruction`, unlike the start)", + "properties": { + "file_content": { + "type": "string" + }, + "file_url": { + "type": "string" + }, + "record_name": { + "type": "string" + }, + "record_type": { + "type": "string" + }, + "record_value": { + "type": "string" + } + }, + "type": "object" + }, + "channel": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "description": "Present once `status` is `verified`", + "type": "string" + } + }, + "required": [ + "session_id", + "domain", + "channel", + "status", + "created_at" + ], + "type": "object" +}
- Changed
get_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "attempts": {}, + "challenge": { + "description": "Challenge details for verification" + }, + "channel": { + "description": "Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken." + }, + "created_at": {}, + "external_user_id": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "identifier": { + "description": "The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it" + }, + "max_attempts": {}, + "proof": { + "description": "Proof token after successful verification" + }, + "status": { + "description": "Current status of the verification" + }, + "type": { + "description": "Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account." + }, + "updated_at": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
get_verification_request2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Multi-asset verification request", + "properties": { + "action_context": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "amount": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "description": { + "type": "string" + }, + "entity": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "The action the person is asked to authorize; null when the request carries none" + }, + "action_type": { + "description": "Type of action for verification request or authorization", + "type": "string" + }, + "assets": { + "items": { + "additionalProperties": {}, + "properties": { + "allowed_channels": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "channel": { + "type": [ + "string", + "null" + ] + }, + "has_proof": { + "type": "boolean" + }, + "identifier": { + "type": [ + "string", + "null" + ] + }, + "required": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_channel": { + "type": "string" + }, + "verified_identifier": { + "type": "string" + } + }, + "required": [ + "type", + "required", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "callback_url": { + "description": "The webhook URL set on the request, if any", + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": "string" + }, + "computed_state": { + "additionalProperties": {}, + "description": "Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces.", + "properties": { + "is_expiring_soon": { + "type": "boolean" + }, + "next_action": { + "additionalProperties": {}, + "properties": { + "code": { + "type": "string" + }, + "label": { + "type": "string" + }, + "role": { + "type": "string" + } + }, + "required": [ + "code", + "role", + "label" + ], + "type": "object" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "is_expiring_soon", + "next_action" + ], + "type": "object" + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "partial_ok": { + "type": "boolean" + }, + "progress": { + "additionalProperties": {}, + "properties": { + "completed": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "completed_required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "optional": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "completed", + "completed_required", + "required", + "optional", + "total" + ], + "type": "object" + }, + "redirect_url": { + "type": [ + "string", + "null" + ] + }, + "reference_id": { + "type": "string" + }, + "status": { + "description": "Status of a verification request", + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "validity_requirement": { + "description": "Required proof freshness as set on the request (e.g. \"7d\"); null when none was set", + "type": [ + "string", + "null" + ] + }, + "verification_url": { + "description": "URL for the verification flow", + "type": "string" + } + }, + "required": [ + "id", + "status", + "assets", + "action_type", + "partial_ok", + "expires_at", + "created_at" + ], + "type": "object" +}
- Changed
get_verified_user2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "external_user_id": {}, + "types_verified": {}, + "verification_count": {}, + "verifications": {} + }, + "type": "object" +}
- Changed
get_webhook_delivery2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Webhook delivery record", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "delivered_at": { + "type": [ + "string", + "null" + ] + }, + "endpoint_id": { + "description": "The webhook endpoint it was sent to. Null for a request's `callback_url` and for a delivery to the account's settings webhook URL before the switch-over to endpoints.", + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "description": "Type of webhook event. `proof.suspended`/`proof.unsuspended` fire for a delegation (`ph_dlg_*`) lifecycle act on the account's own configured webhook_url — not a channel to a separately-addressed delegate (h-fix-delegation-suspend-governance). `proof.reissued`/`delegation.reissued` say a stored token was re-signed under a new key: a reference only (`proof_id` or `handle`, `kid`, `reissued_at`, `token_url`, and the `profile_id` every body carries), never the token; `proof.*` does not cover `delegation.reissued`.", + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_attempt_at": { + "type": [ + "string", + "null" + ] + }, + "max_attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "next_retry_at": { + "type": [ + "string", + "null" + ] + }, + "payload": { + "additionalProperties": {}, + "description": "The event body as stored. Every `proof_token` in it is null: the body POSTed to the receiver carries the token, read from its record at send time, and delivery history keeps no copy.", + "properties": {}, + "type": "object" + }, + "profile_id": { + "description": "The sub-account whose event it was. Null for an account-level event, and for deliveries recorded before #421.", + "type": [ + "string", + "null" + ] + }, + "response_body": { + "description": "The receiver's response body.", + "type": [ + "string", + "null" + ] + }, + "response_status": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "status": { + "description": "Delivery status", + "type": "string" + }, + "token_omitted_reason": { + "description": "Why the last send carried `proof_token: null`. Every attempt, the first included, sends the token the delivery was queued with, or null: a retried delivery carries the same `proof_token` as the first attempt or `proof_token: null`, never a different token. `source_gone`: the record holding the token no longer exists, or (for a delivery stored before tokens were left out of history) could not be identified. `token_absent`: it holds no token, or there was none when the delivery was queued. `token_changed`: its token is no longer the one the delivery was queued with (re-issued or changed since). Null when every token was sent. Absent from an API that predates it.", + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string" + }, + "url": { + "type": "string" + }, + "verification_request_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "verification_request_id", + "endpoint_id", + "profile_id", + "event_type", + "url", + "status", + "attempts", + "max_attempts", + "last_attempt_at", + "next_retry_at", + "delivered_at", + "response_status", + "error_message", + "created_at", + "payload", + "response_body", + "updated_at" + ], + "type": "object" +}
- Added
get_webhook_endpoint - Changed
get_webhook_stats1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Webhook delivery statistics", + "properties": { + "by_status": { + "additionalProperties": {}, + "properties": { + "delivered": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "failed": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "pending": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "pending", + "delivered", + "failed" + ], + "type": "object" + }, + "delivery_rate": { + "description": "Delivered share of all deliveries, a percentage with one decimal and a `%` sign; `0%` when there are none", + "type": "string" + }, + "recent_failures_24h": { + "description": "Failed deliveries last updated in the past 24 hours", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "total", + "by_status", + "delivery_rate", + "recent_failures_24h" + ], + "type": "object" +}
- Changed
invite_circle_member2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "expires_in": {}, + "member_id": { + "description": "MongoDB ObjectId" + }, + "qr_code": { + "description": "QR code data URL for the primary deep link" + }, + "qr_text": { + "description": "UTF-8 text representation of the QR code" + }, + "suggested_share_text": { + "description": "Suggested message to forward with the invite" + }, + "telegram_deep_link": {}, + "token": {}, + "whatsapp_deep_link": {} + }, + "type": "object" +}
- Changed
list_api_keys1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "expires_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "last_used_at": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "replaced_key_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "prefix", + "environment", + "scopes", + "profile_id", + "expires_at", + "created_at", + "replaced_key_ids" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" +}
- Changed
list_assets4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / limitRemoved value: -{ - "description": "Items per page", - "maximum": 100, - "minimum": 1, - "type": "integer" -} - removed
Input schema / properties / pageRemoved value: -{ - "description": "Page number", - "exclusiveMinimum": 0, - "type": "integer" -} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "channel": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "has_proof": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "properties": {}, + "type": "object" + }, + "proof_expires_at": { + "type": "string" + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "channel", + "identifier", + "status", + "proof_expires_at", + "created_at" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" +}
- Changed
list_auth_sessions1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "sessions": {}, + "total": {} + }, + "type": "object" +}
- Changed
list_authorizations3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "authorized_at": { + "type": "string" + }, + "bsuid": { + "type": [ + "string", + "null" + ] + }, + "business_name": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "circle_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "confirmations_sent": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "denied_at": { + "type": "string" + }, + "enrolled": { + "type": "boolean" + }, + "expires_at": { + "type": "string" + }, + "hitl_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "id": { + "type": "string" + }, + "label": { + "type": [ + "string", + "null" + ] + }, + "last_used_at": { + "type": "string" + }, + "phone": { + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "type": "string" + }, + "recipient": { + "type": [ + "string", + "null" + ] + }, + "recipient_display_name": { + "type": [ + "string", + "null" + ] + }, + "revocation_reason": { + "type": "string" + }, + "revoked_at": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_id": { + "type": "string" + } + }, + "required": [ + "id", + "status", + "channel", + "scope", + "business_name", + "recipient_display_name", + "enrolled", + "expires_at", + "confirmations_sent", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "page", + "limit", + "total", + "total_pages" + ], + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Added
list_balance_ledger - Changed
list_circle_member_channels2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channels": {} + }, + "type": "object" +}
- Changed
list_circle_members2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "members": {} + }, + "type": "object" +}
- Changed
list_circles2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Paginated list of Circles", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "type": "string" + }, + "member_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "members": { + "items": { + "additionalProperties": {}, + "properties": { + "enrolled_at": { + "type": [ + "string", + "null" + ] + }, + "enrolled_phone_hint": { + "type": [ + "string", + "null" + ] + }, + "has_telegram": { + "type": "boolean" + }, + "has_whatsapp": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "last_verified_at": { + "type": [ + "string", + "null" + ] + }, + "mesh_opt_out": { + "type": "boolean" + }, + "mesh_opted_in": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "status", + "has_telegram", + "has_whatsapp", + "mesh_opted_in", + "mesh_opt_out", + "enrolled_phone_hint", + "enrolled_at", + "last_verified_at" + ], + "type": "object" + }, + "type": "array" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "owner_name": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "proof_me_enabled": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "name", + "owner_name", + "profile_id", + "environment", + "proof_me_enabled", + "status", + "member_count", + "members", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "page", + "limit", + "total", + "total_pages" + ], + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Changed
list_confirmations6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / end_dateAdded value: +{ + "description": "Only confirmations created on or before this instant (ISO 8601)", + "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))$", + "type": "string" +} - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - added
Input schema / properties / profile_idAdded value: +{ + "description": "Only this sub-account's confirmations (sent through its HITL configs or created by its keys)", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - added
Input schema / properties / start_dateAdded value: +{ + "description": "Only confirmations created on or after this instant (ISO 8601)", + "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))$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Paginated list of confirmations", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "created_at": { + "type": "string" + }, + "hitl_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "id": { + "type": "string" + }, + "message": { + "type": "string" + }, + "proof_token": { + "type": [ + "string", + "null" + ] + }, + "resends": { + "items": { + "additionalProperties": {}, + "properties": { + "actor": { + "additionalProperties": {}, + "properties": { + "api_key_id": { + "type": [ + "string", + "null" + ] + }, + "kind": { + "type": "string" + } + }, + "required": [ + "kind", + "api_key_id" + ], + "type": "object" + }, + "at": { + "type": "string" + }, + "channels": { + "items": { + "additionalProperties": {}, + "properties": { + "recipient": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "recipient" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "at", + "actor", + "channels" + ], + "type": "object" + }, + "type": "array" + }, + "resolved_at": { + "type": [ + "string", + "null" + ] + }, + "response": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "action": { + "type": "string" + }, + "at": { + "type": "string" + }, + "authorization_id": { + "type": [ + "string", + "null" + ] + }, + "channel": { + "type": [ + "string", + "null" + ] + }, + "decided_by": { + "type": [ + "string", + "null" + ] + }, + "kid": { + "type": [ + "string", + "null" + ] + }, + "public_key": { + "type": [ + "string", + "null" + ] + }, + "signature": { + "type": [ + "string", + "null" + ] + }, + "signed_input": { + "type": [ + "string", + "null" + ] + }, + "text": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "action", + "at" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "status": { + "type": "string" + }, + "timeout_at": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "hitl_id", + "message", + "status", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "page", + "limit", + "total", + "total_pages" + ], + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Changed
list_delegations3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": {}, + "pagination": {} + }, + "type": "object" +}
- Changed
list_dns_credentials1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The account's saved DNS provider credentials, ordered by provider", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "created_at": { + "type": "string" + }, + "domains_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "id": { + "type": "string" + }, + "is_valid": { + "type": "boolean" + }, + "last_used_at": { + "type": "string" + }, + "last_validated_at": { + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "validation_error": { + "type": "string" + } + }, + "required": [ + "id", + "provider", + "name", + "is_valid", + "domains_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" +}
- Changed
list_domains1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The account's domains, newest first", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "actual_dns_host": { + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "type": "string" + }, + "dns_mismatch_warning": { + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "type": "boolean" + }, + "oauth_url": { + "type": "string" + }, + "profile_id": { + "type": "string" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "provider_credential_name": { + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "type": "string" + }, + "verification_subtype": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "data" + ], + "type": "object" +}
- Changed
list_emails1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "emails": {} + }, + "type": "object" +}
- Changed
list_hitls4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - added
Input schema / properties / profile_idAdded value: +{ + "description": "Only this sub-account's configs (24 hex characters)", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Paginated list of HITL configurations", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "channels": { + "items": { + "oneOf": [ + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "chat_id": { + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "bsuid": { + "type": "string" + }, + "phone_number": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } + ] + }, + "type": "array" + }, + "circle_id": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "type": "string" + }, + "keypair": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "has_backup_wrapper": { + "type": "boolean" + }, + "has_encrypted_private_key": { + "type": "boolean" + }, + "has_wrapped_dek": { + "type": "boolean" + }, + "kid": { + "type": "string" + } + }, + "required": [ + "kid", + "has_encrypted_private_key", + "has_wrapped_dek", + "has_backup_wrapper" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "timeout_seconds": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "channels", + "timeout_seconds", + "status", + "keypair", + "environment", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + }, + "limits": { + "additionalProperties": {}, + "properties": { + "active_configs": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "max_active_configs": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "max_active_configs", + "active_configs" + ], + "type": "object" + }, + "pagination": { + "additionalProperties": {}, + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "page", + "limit", + "total", + "total_pages" + ], + "type": "object" + } + }, + "required": [ + "data", + "pagination", + "limits" + ], + "type": "object" +}
- Changed
list_incoming_requests1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The verification requests the account was asked to complete, newest first", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "action_type": { + "type": "string" + }, + "assets": { + "items": { + "additionalProperties": {}, + "properties": { + "identifier": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_channel": { + "type": [ + "string", + "null" + ] + }, + "verified_identifier": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type", + "identifier", + "status", + "verified_identifier", + "verified_channel" + ], + "type": "object" + }, + "type": "array" + }, + "completed_at": { + "type": "string" + }, + "computed_state": { + "additionalProperties": {}, + "properties": { + "is_expiring_soon": { + "type": "boolean" + }, + "next_action": { + "additionalProperties": {}, + "properties": { + "code": { + "type": "string" + }, + "label": { + "type": "string" + }, + "role": { + "type": "string" + } + }, + "required": [ + "code", + "role", + "label" + ], + "type": "object" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "is_expiring_soon", + "next_action" + ], + "type": "object" + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "progress": { + "additionalProperties": {}, + "properties": { + "completed": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "completed_required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "optional": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "completed", + "completed_required", + "required", + "optional", + "total" + ], + "type": "object" + }, + "reference_id": { + "type": "string" + }, + "requester": { + "additionalProperties": {}, + "properties": { + "business_name": { + "type": "string" + }, + "logo_url": { + "type": "string" + } + }, + "type": "object" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "status", + "computed_state", + "action_type", + "assets", + "progress", + "expires_at", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "total", + "limit", + "offset" + ], + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Changed
list_my_requests3 fields changed- added
Input schema / properties / api_key_idAdded value: +{ + "description": "Only requests created with this API key or a key it replaced (24 hex characters); an API key may name only itself", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - added
Input schema / properties / profile_idAdded value: +{ + "description": "Only this sub-account's requests (24 hex characters)", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The verification requests the account made, newest first", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "action_type": { + "type": "string" + }, + "agent_name": { + "type": [ + "string", + "null" + ] + }, + "api_key_id": { + "type": [ + "string", + "null" + ] + }, + "api_key_model": { + "type": [ + "string", + "null" + ] + }, + "assets": { + "items": { + "additionalProperties": {}, + "properties": { + "allowed_channels": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "channel": { + "type": [ + "string", + "null" + ] + }, + "identifier": { + "type": [ + "string", + "null" + ] + }, + "required": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_channel": { + "type": [ + "string", + "null" + ] + }, + "verified_identifier": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type", + "identifier", + "status", + "verified_identifier", + "verified_channel", + "channel", + "allowed_channels", + "required" + ], + "type": "object" + }, + "type": "array" + }, + "branding": { + "additionalProperties": {}, + "properties": { + "business_name": { + "type": "string" + }, + "logo_url": { + "type": "string" + } + }, + "type": "object" + }, + "completed_at": { + "type": "string" + }, + "computed_state": { + "additionalProperties": {}, + "properties": { + "is_expiring_soon": { + "type": "boolean" + }, + "next_action": { + "additionalProperties": {}, + "properties": { + "code": { + "type": "string" + }, + "label": { + "type": "string" + }, + "role": { + "type": "string" + } + }, + "required": [ + "code", + "role", + "label" + ], + "type": "object" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "is_expiring_soon", + "next_action" + ], + "type": "object" + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "progress": { + "additionalProperties": {}, + "properties": { + "completed": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "completed_required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "optional": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "completed", + "completed_required", + "required", + "optional", + "total" + ], + "type": "object" + }, + "public_profile_id": { + "type": "string" + }, + "reference_id": { + "type": "string" + }, + "source": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "status", + "computed_state", + "action_type", + "source", + "api_key_id", + "api_key_model", + "agent_name", + "assets", + "progress", + "expires_at", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "offset": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "total", + "limit", + "offset" + ], + "type": "object" + }, + "stats": { + "additionalProperties": {}, + "description": "Requests per status across every page, under the same filters except `status`", + "properties": { + "cancelled": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "completed": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "expired": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "partial": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "pending": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "pending", + "partial", + "completed", + "expired", + "cancelled" + ], + "type": "object" + } + }, + "required": [ + "data", + "pagination", + "stats" + ], + "type": "object" +}
- Changed
list_phones1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "phones": {} + }, + "type": "object" +}
- Changed
list_profiles1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The account's sub-accounts, as their owner sees them", + "properties": { + "count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "max_profiles": { + "description": "How many sub-accounts the plan allows; -1 for no limit", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "profiles": { + "description": "The primary first, then by creation", + "items": { + "additionalProperties": {}, + "properties": { + "avatar_url": { + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "type": "string" + }, + "proof_order": { + "type": "string" + }, + "public_proofs": { + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "profiles", + "count", + "max_profiles" + ], + "type": "object" +}
- Added
list_reissued_proofs - Changed
list_revoked_proofs1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Signed list of revoked proofs", + "properties": { + "count": { + "description": "Number of entries in `revoked`", + "type": "number" + }, + "has_more": { + "description": "True when a source hit its cap and the list may be incomplete — re-baseline and prefer the Token Status List, which never truncates", + "type": "boolean" + }, + "issued_at": { + "description": "When this list was generated", + "type": "string" + }, + "kid": { + "description": "Key id of the signing key, for JWKS lookup", + "type": [ + "string", + "null" + ] + }, + "revoked": { + "items": { + "additionalProperties": {}, + "properties": { + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_type": { + "type": "string" + }, + "public_proof_id": { + "type": [ + "string", + "null" + ] + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "revoked_at": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "proof_id", + "public_proof_id", + "proof_type", + "revoked_at", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "signature": { + "description": "Signature over the payload for offline verification, in the algorithm of the key `kid` names (null when unsigned)", + "type": [ + "string", + "null" + ] + }, + "status_list_uri": { + "description": "The Token Status List endpoint — the scalable status channel that also covers SUSPENDED and can retract entries (an unsuspended bit flips back; a CRL entry cached by a `?since` poller cannot be unpublished)", + "type": "string" + } + }, + "required": [ + "revoked", + "issued_at", + "count", + "has_more", + "status_list_uri", + "signature", + "kid" + ], + "type": "object" +}
- Changed
list_templates3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key"New value: +"The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "available_channels": { + "items": { + "type": "string" + }, + "type": "array" + }, + "available_message_types": { + "items": { + "type": "string" + }, + "type": "array" + }, + "available_variables": { + "items": { + "additionalProperties": {}, + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "description" + ], + "type": "object" + }, + "type": "array" + }, + "custom_templates": { + "items": { + "additionalProperties": {}, + "properties": { + "body": { + "type": "string" + }, + "button_text": { + "type": "string" + }, + "button_url_template": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "id": { + "type": "string" + }, + "is_active": { + "type": "boolean" + }, + "last_fallback_at": { + "type": [ + "string", + "null" + ] + }, + "last_fallback_variables": { + "items": { + "type": "string" + }, + "type": "array" + }, + "message_type": { + "type": "string" + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "subject": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "version": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "channel", + "message_type", + "body" + ], + "type": "object" + }, + "type": "array" + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "sendable": { + "description": "What a template is sent for. Always sent; absent from an API that predates it.", + "items": { + "additionalProperties": {}, + "properties": { + "channel": { + "type": "string" + }, + "message_type": { + "type": "string" + }, + "variables": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "channel", + "message_type", + "variables" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "custom_templates", + "available_channels", + "available_message_types", + "available_variables" + ], + "type": "object" +}
- Changed
list_verification_requests3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "action_type": { + "type": "string" + }, + "asset_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "completed_at": { + "type": "string" + }, + "computed_state": { + "additionalProperties": {}, + "properties": { + "is_expiring_soon": { + "type": "boolean" + }, + "next_action": { + "additionalProperties": {}, + "properties": { + "code": { + "type": "string" + }, + "label": { + "type": "string" + }, + "role": { + "type": "string" + } + }, + "required": [ + "code", + "role", + "label" + ], + "type": "object" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "is_expiring_soon", + "next_action" + ], + "type": "object" + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "progress": { + "additionalProperties": {}, + "properties": { + "completed": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "completed_required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "required": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "completed", + "completed_required", + "required", + "total" + ], + "type": "object" + }, + "reference_id": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "status", + "computed_state", + "action_type", + "asset_count", + "progress", + "expires_at", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "description": "Pagination info in list responses", + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Changed
list_verifications6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / channel / enumPrevious value: -[ - "sms", - "whatsapp", - "telegram", - "email" -]New value: +[ + "whatsapp", + "telegram", + "sms", + "email", + "dns", + "http", + "auto", + "github", + "google", + "facebook", + "x", + "linkedin", + "instagram", + "youtube", + "tiktok", + "ethereum", + "solana", + "bitcoin", + "coinbase", + "kraken", + "telegram_bot_token" +] - removed
Input schema / properties / external_user_idRemoved value: -{ - "description": "Filter by external user ID", - "type": "string" -} - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - added
Input schema / properties / typeAdded value: +{ + "description": "Filter by asset type", + "enum": [ + "phone", + "email", + "domain", + "social", + "wallet", + "account", + "telegram_bot" + ], + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Paginated list of verifications", + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "channel": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "channel", + "status", + "environment", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "description": "Pagination info in list responses", + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Changed
list_verified_users3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": {}, + "pagination": {} + }, + "type": "object" +}
- Changed
list_webhook_deliveries6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / endpoint_idAdded value: +{ + "description": "Only deliveries to this webhook endpoint", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - added
Input schema / properties / page / maximumAdded value: +9007199254740991 - added
Input schema / properties / profile_idAdded value: +{ + "description": "Only this sub-account's deliveries", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - added
Input schema / properties / verification_request_idAdded value: +{ + "description": "Only deliveries for this verification request", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": { + "items": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "delivered_at": { + "type": [ + "string", + "null" + ] + }, + "endpoint_id": { + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_attempt_at": { + "type": [ + "string", + "null" + ] + }, + "max_attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "next_retry_at": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "response_status": { + "anyOf": [ + { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "status": { + "type": "string" + }, + "url": { + "type": "string" + }, + "verification_request_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "verification_request_id", + "endpoint_id", + "profile_id", + "event_type", + "url", + "status", + "attempts", + "max_attempts", + "last_attempt_at", + "next_retry_at", + "delivered_at", + "response_status", + "error_message", + "created_at" + ], + "type": "object" + }, + "type": "array" + }, + "pagination": { + "additionalProperties": {}, + "description": "Pagination info in list responses", + "properties": { + "limit": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "page": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "total_pages": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "type": "object" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" +}
- Added
list_webhook_endpoints - Changed
poll_chat_id_discovery2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "chat_id": {}, + "status": {} + }, + "type": "object" +}
- Changed
preview_template3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key"New value: +"The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "is_valid": {}, + "preview": {}, + "validation_errors": { + "description": "What a save would refuse." + }, + "warnings": { + "description": "What a save would warn about; never makes `is_valid` false. Always sent; absent from an API that predates it." + } + }, + "type": "object" +}
- Changed
regenerate_api_key2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A newly created or regenerated API key, with its full value — the one response that carries it.", + "properties": { + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "key": { + "description": "The full API key. Returned only in this response; it cannot be read again.", + "type": "string" + }, + "name": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "profile_id": { + "description": "Sub-account (PublicProfile) the key is bound to; null for unbound keys.", + "type": [ + "string", + "null" + ] + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "warning": { + "type": "string" + } + }, + "required": [ + "id", + "key", + "name", + "prefix", + "environment", + "scopes", + "profile_id", + "created_at", + "warning" + ], + "type": "object" +}
- Changed
remove_circle_member2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": {}, + "type": "object" +}
- Changed
remove_circle_member_channel2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": {}, + "type": "object" +}
- Changed
remove_email2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "authorizations_revoked": {}, + "circles_repointed": { + "description": "Phones only: circles that now reach the owner at `new_primary`; 0 for an email." + }, + "hitl_configs_without_approver": {}, + "identifier": { + "description": "Masked." + }, + "lookalike_watch": {}, + "new_primary": { + "description": "The row that becomes (or became) primary when the removed one was; null otherwise." + }, + "notice": {}, + "proofs_revoked": {}, + "removed_id": {}, + "sessions_invalidated": { + "description": "Other listed devices signed out, idle ones included; the calling session stays. A device missing from the list — signed in before the list held idle devices, or one whose listing could not be recorded — is not counted, so read `sessions_signed_out` for whether every other device was signed out." + }, + "sessions_signed_out": { + "description": "Every other device was signed out, idle ones included; the calling session stays. False when that could not be done — the removal itself still happened." + }, + "success": { + "description": "Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major." + }, + "type": {} + }, + "type": "object" +}
- Changed
remove_phone2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "authorizations_revoked": {}, + "circles_repointed": { + "description": "Phones only: circles that now reach the owner at `new_primary`; 0 for an email." + }, + "hitl_configs_without_approver": {}, + "identifier": { + "description": "Masked." + }, + "lookalike_watch": {}, + "new_primary": { + "description": "The row that becomes (or became) primary when the removed one was; null otherwise." + }, + "notice": {}, + "proofs_revoked": {}, + "removed_id": {}, + "sessions_invalidated": { + "description": "Other listed devices signed out, idle ones included; the calling session stays. A device missing from the list — signed in before the list held idle devices, or one whose listing could not be recorded — is not counted, so read `sessions_signed_out` for whether every other device was signed out." + }, + "sessions_signed_out": { + "description": "Every other device was signed out, idle ones included; the calling session stays. False when that could not be done — the removal itself still happened." + }, + "success": { + "description": "Always `true`. The 1.x Go, PHP and Python SDK types carry it as a string, as released; it is typed boolean in the next major." + }, + "type": {} + }, + "type": "object" +}
- Changed
render_auth_link1 field changed- removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
render_template4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key"New value: +"The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key" - removed
Input schema / properties / variables / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "rendered": {} + }, + "type": "object" +}
- Changed
request_hitl_authorization2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Response from requesting authorization consent for HITL channels", + "properties": { + "authorizations": { + "items": { + "additionalProperties": {}, + "properties": { + "authorization_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "recipient": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "channel", + "recipient", + "authorization_id", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "hitl_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "hitl_id", + "authorizations", + "message" + ], + "type": "object" +}
- Changed
resend_domain_email2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A verification code emailed to an address on the domain", + "properties": { + "data": { + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "type": "string" + }, + "dns_mismatch_warning": { + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "type": "boolean" + }, + "oauth_url": { + "type": "string" + }, + "profile_id": { + "type": "string" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "provider_credential_name": { + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "type": "string" + }, + "verification_subtype": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "email_sent_to": { + "description": "Sent when a code was sent; absent when the domain was already verified.", + "type": "string" + }, + "expires_in_minutes": { + "description": "Sent with `email_sent_to`.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "data", + "message" + ], + "type": "object" +}
- Changed
resend_email_otp2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
resend_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "expires_at": {}, + "message": {}, + "success": {} + }, + "type": "object" +}
- Changed
retry_webhook_delivery2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "delivery_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "message": { + "type": "string" + }, + "next_retry_at": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "delivery_id", + "next_retry_at" + ], + "type": "object" +}
- Changed
revoke_api_key2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
revoke_asset2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "asset_id": {}, + "delegations_revoked": { + "description": "Domains only: the delegations revoked with the proofs. Re-verifying does not bring them back." + }, + "domain_status": { + "description": "Domains only: `reverification_required` — the domain stays on the account and needs re-verification before anything can be issued from it." + }, + "identifier": { + "description": "Masked for phones and emails; a domain travels in clear." + }, + "notice": {}, + "outcome": { + "description": "`not_found` is also the answer for an asset the account does not own." + }, + "revoked_asset_ids": { + "description": "Every asset of the same identifier this call revoked with it, the named one included — a phone holds one asset per channel, a domain one per verification." + }, + "success": { + "description": "Always `true`" + }, + "type": {} + }, + "type": "object" +}
- Changed
revoke_auth_session2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
revoke_authorization2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Authorization granting permission to send confirmations via a specific channel", + "properties": { + "authorized_at": { + "type": "string" + }, + "bsuid": { + "description": "WhatsApp Business-Scoped User ID", + "type": [ + "string", + "null" + ] + }, + "business_name": { + "type": "string" + }, + "channel": { + "description": "Channel authorized for sending confirmations", + "type": "string" + }, + "circle_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "confirmations_sent": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "denied_at": { + "description": "When the recipient refused — the mirror of `authorized_at` for a `denied` row (a challenger cancellation stamps it too). Absent unless the authorization was denied; before it existed such a row carried no decision time at all, only `updated_at`.", + "type": "string" + }, + "enrolled": { + "description": "Whether the approver has enrolled an encryption key. A confirmation can be sealed to an approver only once this is true; consent alone (`status: active`) is not enough.", + "type": "boolean" + }, + "expires_at": { + "type": "string" + }, + "hitl_id": { + "allOf": [ + { + "type": "string" + }, + {} + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "label": { + "description": "Owner-assigned human label for this approver (F22); null when unset. Surfaces lead with it, falling back to the masked recipient.", + "type": [ + "string", + "null" + ] + }, + "last_used_at": { + "type": "string" + }, + "phone": { + "type": [ + "string", + "null" + ] + }, + "proof_token": { + "description": "Signed proof of the recipient's decision, minted when they approved or refused, for both scopes. Absent while no decision has been made.", + "type": "string" + }, + "recipient": { + "description": "Channel-specific recipient identifier (chat_id for Telegram, phone or BSUID for WhatsApp)", + "type": [ + "string", + "null" + ] + }, + "recipient_display_name": { + "description": "The approver's own messenger name (\"First Last @username\"), captured when they approved over Telegram; null when none was captured. Chosen by the approver, not verified.", + "type": [ + "string", + "null" + ] + }, + "revocation_reason": { + "type": "string" + }, + "revoked_at": { + "type": "string" + }, + "scope": { + "description": "Scope of the authorization. `identity_challenge` is the Proof of Me scope.", + "type": "string" + }, + "status": { + "description": "Status of an authorization", + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_id": { + "description": "MongoDB ObjectId", + "type": "string" + } + }, + "required": [ + "id", + "status", + "channel", + "scope", + "business_name", + "recipient_display_name", + "enrolled", + "expires_at", + "confirmations_sent", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
revoke_delegation2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "control_proof": { + "description": "The control proof handle this delegation points down to" + }, + "created_at": {}, + "delegate": { + "description": "Typed delegate identifier" + }, + "delegation_id": { + "description": "Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint" + }, + "effective_status": { + "description": "DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects" + }, + "environment": {}, + "expires_at": { + "description": "Never later than the control proof's own expiry at issuance (effective expiry is min of the two)" + }, + "id": { + "description": "MongoDB ObjectId" + }, + "is_valid": { + "description": "True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above" + }, + "issued_at": {}, + "principal": { + "description": "The proven domain that authorized the delegate — derived from the control proof, never client input" + }, + "revoked_at": {}, + "revoked_reason": {}, + "scope": { + "description": "Deprecated. Delegation schema 2.0 carries no scope; this array stays for the SDKs released before it: the scope a delegation issued before schema 2.0 was stored with, otherwise empty. Removed in the next major version." + }, + "status": { + "description": "The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on" + } + }, + "type": "object" +}
- Changed
revoke_proof3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / reason / descriptionPrevious value: -"Reason for revocation"New value: +"Why the proof is revoked, one of: user_request, fraud, key_compromise, asset_transferred, other. A delegation proof (ph_dlg_*) refuses asset_transferred. The API refuses any other value. Defaults to user_request." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "delegations_revoked": { + "description": "Control proofs only: the delegations revoked with the proof. Re-verifying the domain does not bring them back." + }, + "domain_status": { + "description": "Control proofs only: the Domain row's status after the act (`reverification_required` after the cascade); null when the account has no Domain row for the name." + }, + "owned_domain": { + "description": "Control proofs only: true when the account OWNS the domain (a Domain row or a domain asset for the name) and the whole-domain cascade ran — every proof of the domain and every delegation issued from it revoked, the domain demoted to `reverification_required`. False for a bare verification of somebody else's domain: that proof and the delegations anchored on it only." + }, + "principal": { + "description": "Control proofs only: the domain the proof is about." + }, + "proof_id": { + "description": "Public proof handle (`ph_ctl_*`/`ph_dlg_*`). Present when the proof was addressed by handle." + }, + "proof_type": { + "description": "Which record carries the revoked proof (`verification`, `user_asset`, `verification_request`, `delegation`, …). Present when the proof was addressed by handle." + }, + "reason": {}, + "revoked_at": {}, + "success": {}, + "verification_id": { + "description": "Present only when the revoked proof belongs to a verification." + } + }, + "type": "object" +}
- Added
rotate_callback_secret - Added
rotate_webhook_endpoint_secret - Changed
search2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "data": {}, + "total": {} + }, + "type": "object" +}
- Changed
send_account_email2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": {}, + "email_error": {}, + "email_sent": {}, + "id": {} + }, + "type": "object" +}
- Changed
set_primary_email2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
set_primary_phone2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Generic success response", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" +}
- Changed
set_primary_profile2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account as its owner sees it", + "properties": { + "avatar_url": { + "description": "A URL or a data URI; null once cleared", + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "description": "Theme of this sub-account's emails; null when unset (read as `dark`).", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "description": "The public id used in profile URLs", + "type": "string" + }, + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "description": "Support address shown in this sub-account's messages; null when unset.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "description": "Profile theme customization", + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "description": "Absent until a username is claimed", + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "description": "Always 'basic'; no levels are computed; removed in the next major.", + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
setup_domain_email3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / from_email / patternAdded value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
share_request_email4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / emailAdded value: +{ + "description": "Recipient email address the verification link is sent to", + "format": "email", + "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "id" -]New value: +[ + "id", + "email" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The verification link was emailed", + "properties": { + "message": { + "type": "string" + }, + "messageId": { + "description": "The email provider's message id; absent in test mode", + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ], + "type": "object" +}
- Changed
start_2fa8 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / action_type / descriptionPrevious value: -"The sensitive action requiring 2FA"New value: +"The sensitive action requiring 2FA: any action type the API documents" - changed
Input schema / properties / action_type / enumPrevious value: -[ - "api_key_view", - "api_key_create", - "api_key_revoke", - "api_key_regenerate", - "phone_add", - "phone_remove", - "email_add", - "email_remove", - "account_delete", - "revocation_bulk", - "domain_remove", - "profile_delete", - "phone_primary", - "email_primary" -]New value: +[ + "api_key_view", + "api_key_create", + "api_key_revoke", + "api_key_regenerate", + "phone_add", + "phone_remove", + "phone_primary", + "email_add", + "email_remove", + "email_primary", + "account_delete", + "master_key_change", + "hitl_key_rotate", + "revocation_bulk", + "settings_write", + "profile_update", + "templates_write", + "webhook_write", + "delegation_lifecycle", + "company_update", + "domain_remove", + "profile_delete", + "account_delete_cancel", + "plan_change", + "auto_top_up_change" +] - added
Input schema / properties / phone_idAdded value: +{ + "description": "Optional: specific UserPhone id for phone-channel 2FA", + "type": "string" +} - added
Input schema / properties / single_useAdded value: +{ + "description": "Whether the grant is consumed on first use. Server forces true for destructive action types. Defaults to true.", + "type": "boolean" +} - changed
Input schema / properties / targets / descriptionPrevious value: -"The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the project id; account_delete: your own user id (get_current_user). Leave out for the other action types."New value: +"The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the sub-account id; account_delete: your own user id (get_current_user). Leave out for the other action types." - added
Input schema / properties / ttl_secondsAdded value: +{ + "description": "Requested grant lifetime in seconds. Server caps to 300s for destructive action types, 86400s for configuration scopes. Defaults to 300 if omitted.", + "maximum": 86400, + "minimum": 60, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "available_emails": { + "description": "The addresses the code may go to; call again with one of their ids as `email_id`" + }, + "channel": {}, + "deep_link": { + "description": "Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`)" + }, + "email": { + "description": "The address the code went to, masked (`email` only)" + }, + "email_sent": { + "description": "`true` when the code was emailed (`email` only)" + }, + "expires_at": {}, + "instructions": { + "description": "One line telling the person what to do" + }, + "message": {}, + "qr_code": { + "description": "Base64-encoded PNG QR code for `deep_link`" + }, + "qr_text": { + "description": "UTF-8 text QR for `deep_link`, for terminal/agent rendering" + }, + "requires_email_selection": { + "description": "Always `true`: no session was started, pick an address and start again" + }, + "second_method_recommended": { + "description": "Present (true) when the step-up uses the channel the account signed in with, because the account has no other; adding a second channel is recommended" + }, + "session_id": {}, + "sms_code": { + "description": "The short code the person texts (`sms` only)" + }, + "sms_dids": { + "description": "Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code." + }, + "sms_message": { + "description": "The message to send (`sms` only)" + }, + "status": {} + }, + "type": "object" +}
- Changed
start_2fa_for_action5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / action_type / descriptionPrevious value: -"The sensitive action the 2FA grant will authorize. Destructive scopes (api_key_*, account_delete, phone_remove, email_remove, phone_primary, email_primary, revocation_bulk, domain_remove, profile_delete) are capped at 5 min TTL + forced single-use. Configuration scopes (settings_write, profile_update, templates_write) allow up to 24h TTL with caller-chosen single_use. See config/twoFAPolicy.ts on the backend for the canonical policy."New value: +"The sensitive action the 2FA grant will authorize: any action type the API documents. The server caps each by its policy: destructive types (e.g. api_key_*, *_remove, revocation_bulk, account_delete) to 5 min TTL and single use; configuration scopes (e.g. settings_write, webhook_write) up to 24h with caller-chosen single_use." - changed
Input schema / properties / action_type / enumPrevious value: -[ - "api_key_create", - "api_key_revoke", - "api_key_regenerate", - "api_key_view", - "phone_remove", - "email_remove", - "account_delete", - "revocation_bulk", - "domain_remove", - "profile_delete", - "phone_primary", - "email_primary", - "settings_write", - "profile_update", - "templates_write" -]New value: +[ + "api_key_view", + "api_key_create", + "api_key_revoke", + "api_key_regenerate", + "phone_add", + "phone_remove", + "phone_primary", + "email_add", + "email_remove", + "email_primary", + "account_delete", + "master_key_change", + "hitl_key_rotate", + "revocation_bulk", + "settings_write", + "profile_update", + "templates_write", + "webhook_write", + "delegation_lifecycle", + "company_update", + "domain_remove", + "profile_delete", + "account_delete_cancel", + "plan_change", + "auto_top_up_change" +] - changed
Input schema / properties / targets / descriptionPrevious value: -"The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the project id; account_delete: your own user id (get_current_user). Leave out for the other action types."New value: +"The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the sub-account id; account_delete: your own user id (get_current_user). Leave out for the other action types." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "available_emails": { + "description": "The addresses the code may go to; call again with one of their ids as `email_id`" + }, + "channel": {}, + "deep_link": { + "description": "Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`)" + }, + "email": { + "description": "The address the code went to, masked (`email` only)" + }, + "email_sent": { + "description": "`true` when the code was emailed (`email` only)" + }, + "expires_at": {}, + "instructions": { + "description": "One line telling the person what to do" + }, + "message": {}, + "qr_code": { + "description": "Base64-encoded PNG QR code for `deep_link`" + }, + "qr_text": { + "description": "UTF-8 text QR for `deep_link`, for terminal/agent rendering" + }, + "requires_email_selection": { + "description": "Always `true`: no session was started, pick an address and start again" + }, + "second_method_recommended": { + "description": "Present (true) when the step-up uses the channel the account signed in with, because the account has no other; adding a second channel is recommended" + }, + "session_id": {}, + "sms_code": { + "description": "The short code the person texts (`sms` only)" + }, + "sms_dids": { + "description": "Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code." + }, + "sms_message": { + "description": "The message to send (`sms` only)" + }, + "status": {} + }, + "type": "object" +}
- Changed
start_add_email3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / email / patternAdded value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "An email-add session: a code was emailed to the address", + "properties": { + "channel": { + "type": "string" + }, + "email": { + "type": "string" + }, + "email_error": { + "description": "Why the code did not go out; present only when `email_sent` is false", + "type": "string" + }, + "email_sent": { + "description": "Whether the code went out; the session is started either way", + "type": "boolean" + }, + "expires_at": { + "type": "string" + }, + "instructions": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "session_id", + "email", + "channel", + "status", + "expires_at", + "instructions", + "email_sent" + ], + "type": "object" +}
- Changed
start_add_phone2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A phone-add session: the person proves the number by sending from it over `channel`", + "properties": { + "channel": { + "type": "string" + }, + "deep_link": { + "description": "Opens Telegram or WhatsApp with what the person sends (`telegram`, `whatsapp`)", + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "instructions": { + "description": "One line telling the person what to do", + "type": "string" + }, + "qr_code": { + "description": "Base64-encoded PNG QR code for `deep_link`", + "type": "string" + }, + "qr_text": { + "description": "UTF-8 text QR for `deep_link`, for terminal/agent rendering", + "type": "string" + }, + "session_id": { + "type": "string" + }, + "sms_code": { + "description": "The short code the person texts (`sms` only)", + "type": "string" + }, + "sms_dids": { + "additionalProperties": {}, + "description": "Our SMS numbers, one entry per region and always all three. A region with no number configured carries an empty `did` and no QR code.", + "properties": { + "americas": { + "additionalProperties": {}, + "properties": { + "did": { + "type": "string" + }, + "flag": { + "type": "string" + }, + "label": { + "type": "string" + }, + "qr_code": { + "type": "string" + }, + "qr_text": { + "type": "string" + } + }, + "required": [ + "did", + "label", + "flag" + ], + "type": "object" + }, + "europe": { + "additionalProperties": {}, + "properties": { + "did": { + "type": "string" + }, + "flag": { + "type": "string" + }, + "label": { + "type": "string" + }, + "qr_code": { + "type": "string" + }, + "qr_text": { + "type": "string" + } + }, + "required": [ + "did", + "label", + "flag" + ], + "type": "object" + }, + "israel": { + "additionalProperties": {}, + "properties": { + "did": { + "type": "string" + }, + "flag": { + "type": "string" + }, + "label": { + "type": "string" + }, + "qr_code": { + "type": "string" + }, + "qr_text": { + "type": "string" + } + }, + "required": [ + "did", + "label", + "flag" + ], + "type": "object" + } + }, + "required": [ + "americas", + "europe", + "israel" + ], + "type": "object" + }, + "sms_message": { + "description": "The message to send (`sms` only)", + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "session_id", + "channel", + "status", + "expires_at", + "instructions" + ], + "type": "object" +}
- Changed
start_domain_email_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A verification code emailed to an address on the domain", + "properties": { + "data": { + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "type": "string" + }, + "dns_mismatch_warning": { + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "type": "boolean" + }, + "oauth_url": { + "type": "string" + }, + "profile_id": { + "type": "string" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "provider_credential_name": { + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "type": "string" + }, + "verification_subtype": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "email_sent_to": { + "description": "Sent when a code was sent; absent when the domain was already verified.", + "type": "string" + }, + "expires_in_minutes": { + "description": "Sent with `email_sent_to`.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "data", + "message" + ], + "type": "object" +}
- Changed
start_domain_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "dns_record": {}, + "domain": {}, + "http_file": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "provider": {}, + "status": {}, + "verification_method": {} + }, + "type": "object" +}
- Changed
start_login3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / email / patternAdded value: +"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "Authentication channel" + }, + "deep_link": {}, + "expires_at": {}, + "id": {}, + "instructions": {}, + "qr_code": { + "description": "Base64-encoded QR code image" + }, + "qr_text": { + "description": "UTF-8 text representation of the QR code for terminal/agent display" + }, + "status": { + "description": "Status of an auth session. `completed_elsewhere` (terminal, no cookies): an email sign-in the person completed in ANOTHER browser by pressing \"Sign in here\" on the link's page — this session will never become `verified`." + }, + "type": {}, + "user_id": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
start_user_domain_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A self-service domain verification session", + "properties": { + "challenge": { + "additionalProperties": {}, + "description": "What to publish: a TXT record (`dns`) or a file on the site (`http`)", + "properties": { + "file_content": { + "type": "string" + }, + "file_path": { + "type": "string" + }, + "file_url": { + "type": "string" + }, + "instruction": { + "type": "string" + }, + "record_name": { + "type": "string" + }, + "record_type": { + "type": "string" + }, + "record_value": { + "type": "string" + } + }, + "required": [ + "instruction" + ], + "type": "object" + }, + "channel": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "session_id", + "domain", + "channel", + "status", + "expires_at", + "challenge" + ], + "type": "object" +}
- Changed
submit_verification_code2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Result of submitting the code we emailed", + "properties": { + "attempts": { + "description": "Codes submitted so far, this one included", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "attempts_remaining": { + "description": "Present while `pending`", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "max_attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "message": { + "description": "Present when the code was wrong (`pending`) or the attempts are used up (`failed`)", + "type": "string" + }, + "proof": { + "additionalProperties": {}, + "description": "Present when the code was right", + "properties": { + "expires_at": { + "type": "string" + }, + "token": { + "type": "string" + } + }, + "required": [ + "token", + "expires_at" + ], + "type": "object" + }, + "status": { + "description": "Current status of the verification", + "type": "string" + }, + "verified_at": { + "description": "Present when the code was right", + "type": "string" + } + }, + "required": [ + "id", + "status", + "attempts", + "max_attempts" + ], + "type": "object" +}
- Changed
test_verify2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken.", + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "identifier": { + "type": "string" + }, + "proof_expires_at": { + "type": "string" + }, + "proof_token": { + "type": "string" + }, + "status": { + "type": "string" + }, + "test_mode": { + "type": "boolean" + }, + "type": { + "description": "Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account.", + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "channel", + "status", + "identifier", + "verified_at", + "proof_token", + "proof_expires_at", + "test_mode" + ], + "type": "object" +}
- Changed
trigger_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "attempts": {}, + "challenge": { + "description": "Challenge details for verification" + }, + "channel": { + "description": "Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken." + }, + "created_at": {}, + "external_user_id": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "identifier": { + "description": "The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it" + }, + "max_attempts": {}, + "proof": { + "description": "Proof token after successful verification" + }, + "status": { + "description": "Current status of the verification" + }, + "type": { + "description": "Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account." + }, + "updated_at": {}, + "verified_at": {} + }, + "type": "object" +}
- Changed
update_circle2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "created_at": {}, + "environment": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "member_count": {}, + "members": {}, + "name": {}, + "owner_name": { + "description": "How this Circle's members know its owner; null when unset" + }, + "profile_id": {}, + "proof_me_enabled": {}, + "status": { + "description": "Lifecycle state of a Circle (archived = soft-retired)" + }, + "updated_at": {}, + "user_id": {} + }, + "type": "object" +}
- Changed
update_hitl4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / channels / items / anyOfRemoved value: -[ - { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": false, - "properties": { - "chat_id": { - "maxLength": 50, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "chat_id" - ], - "type": "object" - }, - "type": { - "const": "telegram", - "type": "string" - } - }, - "required": [ - "type", - "config" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "config": { - "additionalProperties": false, - "properties": { - "bsuid": { - "description": "WhatsApp Business-Scoped User ID (e.g. US.abc123...)", - "pattern": "^[A-Z]{2}\\.[a-zA-Z0-9]{10,140}$", - "type": "string" - }, - "phone_number": { - "description": "Phone number in E.164 format", - "pattern": "^\\+?[1-9]\\d{6,14}$", - "type": "string" - } - }, - "type": "object" - }, - "type": { - "const": "whatsapp", - "type": "string" - } - }, - "required": [ - "type", - "config" - ], - "type": "object" - } -] - added
Input schema / properties / channels / items / oneOfAdded value: +[ + { + "properties": { + "config": { + "properties": { + "chat_id": { + "maxLength": 50, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "properties": { + "config": { + "properties": { + "bsuid": { + "description": "WhatsApp Business-Scoped User ID (e.g. US.abc123...)", + "pattern": "^[A-Z]{2}\\.[a-zA-Z0-9]{10,140}$", + "type": "string" + }, + "phone_number": { + "description": "Phone number in E.164 format", + "pattern": "^\\+?[1-9]\\d{6,14}$", + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "HITL configuration with messaging channels and timeout", + "properties": { + "channels": { + "items": { + "oneOf": [ + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "chat_id": { + "type": "string" + } + }, + "required": [ + "chat_id" + ], + "type": "object" + }, + "type": { + "const": "telegram", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + }, + { + "additionalProperties": {}, + "properties": { + "config": { + "additionalProperties": {}, + "properties": { + "bsuid": { + "type": "string" + }, + "phone_number": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "const": "whatsapp", + "type": "string" + } + }, + "required": [ + "type", + "config" + ], + "type": "object" + } + ] + }, + "type": "array" + }, + "circle_id": { + "description": "Backing Circle for a circle-backed Approvals config (null for channel-list configs)", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "keypair": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "has_backup_wrapper": { + "type": "boolean" + }, + "has_encrypted_private_key": { + "type": "boolean" + }, + "has_wrapped_dek": { + "type": "boolean" + }, + "kid": { + "type": "string" + } + }, + "required": [ + "kid", + "has_encrypted_private_key", + "has_wrapped_dek", + "has_backup_wrapper" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Encryption keypair metadata (null if not configured)" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "profile_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Status of a HITL configuration", + "type": "string" + }, + "timeout_seconds": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "description": "Owner user ID (useful for SDK encryption AAD)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "channels", + "timeout_seconds", + "status", + "keypair", + "environment", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
update_my_profile7 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / avatar_url / anyOfPrevious value: -[ - { - "anyOf": [ - { - "not": {} - }, - { - "maxLength": 500000, - "type": "string" - } - ] - }, - { - "type": "null" - } -]New value: +[ + { + "maxLength": 500000, + "type": "string" + }, + { + "type": "null" + } +] - removed
Input schema / properties / custom_links / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / custom_links / items / properties / display_order / maximumAdded value: +9007199254740991 - added
Input schema / properties / show_delegationsAdded value: +{ + "description": "List the published, in-force delegations for the domains the profile shows (default true)", + "type": "boolean" +} - removed
Input schema / properties / theme / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account as its owner sees it", + "properties": { + "avatar_url": { + "description": "A URL or a data URI; null once cleared", + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "description": "Theme of this sub-account's emails; null when unset (read as `dark`).", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "description": "The public id used in profile URLs", + "type": "string" + }, + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "description": "Support address shown in this sub-account's messages; null when unset.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "description": "Profile theme customization", + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "description": "Absent until a username is claimed", + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "description": "Always 'basic'; no levels are computed; removed in the next major.", + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
update_profile10 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / avatar_url / anyOfPrevious value: -[ - { - "anyOf": [ - { - "not": {} - }, - { - "maxLength": 100000, - "type": "string" - } - ] - }, - { - "type": "null" - } -]New value: +[ + { + "maxLength": 100000, + "type": "string" + }, + { + "type": "null" + } +] - removed
Input schema / properties / custom_links / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / custom_links / items / properties / display_order / maximumAdded value: +9007199254740991 - changed
Input schema / properties / email_theme / descriptionPrevious value: -"Theme of this project's emails"New value: +"Theme of this sub-account's emails" - added
Input schema / properties / show_delegationsAdded value: +{ + "description": "List the published, in-force delegations for the domains the profile shows (default true)", + "type": "boolean" +} - changed
Input schema / properties / support_email / anyOfPrevious value: -[ - { - "anyOf": [ - { - "not": {} - }, - { - "format": "email", - "maxLength": 254, - "type": "string" - } - ], - "description": "Support email this project's messages show" - }, - { - "type": "null" - } -]New value: +[ + { + "description": "Support email this sub-account's messages show", + "format": "email", + "maxLength": 254, + "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / support_email / descriptionPrevious value: -"Support email this project's messages show (null to remove)"New value: +"Support email this sub-account's messages show (null to remove)" - removed
Input schema / properties / theme / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account as its owner sees it", + "properties": { + "avatar_url": { + "description": "A URL or a data URI; null once cleared", + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": "string" + }, + "business_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "custom_links": { + "items": { + "additionalProperties": {}, + "properties": { + "_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "icon": { + "type": "string" + }, + "is_visible": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_id", + "title", + "url", + "is_visible", + "display_order" + ], + "type": "object" + }, + "type": "array" + }, + "display_name": { + "type": "string" + }, + "email_theme": { + "description": "Theme of this sub-account's emails; null when unset (read as `dark`).", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "is_business": { + "type": "boolean" + }, + "is_primary": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "profile_id": { + "description": "The public id used in profile URLs", + "type": "string" + }, + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + }, + "show_delegations": { + "type": "boolean" + }, + "show_proof_channels": { + "type": "boolean" + }, + "show_verification_dates": { + "type": "boolean" + }, + "support_email": { + "description": "Support address shown in this sub-account's messages; null when unset.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "additionalProperties": {}, + "description": "Profile theme customization", + "properties": { + "background_color": { + "type": "string" + }, + "background_type": { + "type": "string" + }, + "font_style": { + "type": "string" + }, + "gradient_end": { + "type": "string" + }, + "gradient_start": { + "type": "string" + }, + "primary_color": { + "type": "string" + } + }, + "type": "object" + }, + "updated_at": { + "type": "string" + }, + "username": { + "description": "Absent until a username is claimed", + "type": [ + "string", + "null" + ] + }, + "verification_level": { + "description": "Always 'basic'; no levels are computed; removed in the next major.", + "type": "string" + }, + "view_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + } + }, + "required": [ + "id", + "profile_id", + "is_primary", + "verification_level", + "is_business", + "public_proofs", + "proof_order", + "custom_links", + "theme", + "is_public", + "show_verification_dates", + "show_proof_channels", + "show_delegations", + "support_email", + "email_theme", + "view_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
update_profile_proofs5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / proof_orderAdded value: +{ + "description": "Who orders the shown proofs: `default` (domain, social, Telegram bot, email, phone, wallet, then display_order) or `owner` (display_order alone). Omitted, the profile keeps its current setting.", + "enum": [ + "default", + "owner" + ], + "type": "string" +} - removed
Input schema / properties / proofs / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / proofs / items / properties / display_order / maximumAdded value: +9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account's shown proofs after an update", + "properties": { + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "public_proofs", + "proof_order" + ], + "type": "object" +}
- Changed
update_public_proofs5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / proof_orderAdded value: +{ + "description": "Who orders the shown proofs: `default` (domain, social, Telegram bot, email, phone, wallet, then display_order) or `owner` (display_order alone). Omitted, the profile keeps its current setting.", + "enum": [ + "default", + "owner" + ], + "type": "string" +} - removed
Input schema / properties / proofs / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / proofs / items / properties / display_order / maximumAdded value: +9007199254740991 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "A sub-account's shown proofs after an update", + "properties": { + "proof_order": { + "description": "Who decided the order of a profile's proofs. `default`: domain, social account, Telegram bot, email, phone, wallet, then each proof's `display_order`. `owner`: the owner's `display_order` alone — send it when the owner reorders. The first shown proof that is not hidden leads the profile's preview card, share tags and badge. Omitted on an update, the profile keeps its current setting.", + "type": "string" + }, + "public_proofs": { + "description": "The shown proofs, in the order the public profile shows them", + "items": { + "additionalProperties": {}, + "properties": { + "asset_id": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "delegate_type": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "display_order": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "display_value": { + "type": "string" + }, + "is_revoked": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "mask_level": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "asset_id", + "type", + "display_value", + "verified_at", + "is_visible", + "display_order", + "mask_level" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "public_proofs", + "proof_order" + ], + "type": "object" +}
- Changed
update_settings4 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / hitlAdded value: +{ + "description": "Approval-setup settings", + "properties": { + "approver_password_min_length": { + "anyOf": [ + { + "maximum": 128, + "minimum": 8, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The shortest encryption password an approver may choose when enrolling (8-128); null removes the minimum. Applies to new enrolments only." + } + }, + "type": "object" +} - removed
Input schema / properties / webhook / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "hitl": { + "description": "Approval-setup settings." + }, + "proof_expiry_days": { + "description": "Default lifetime in days of newly issued verification proofs, or null when the account has never set one. Confirmation-decision proofs do not use it." + }, + "success": {}, + "webhook": { + "description": "Outbound webhook configuration — DEPRECATED (#421). An account switched over to webhook endpoints sees its account-wide (`legacy`) endpoint here: `url` is null while that endpoint is disabled, a `url` write updates or creates it, `url: null` disables it (its secret is kept), and `rotate_secret` rotates its secret. An account not yet switched over sees its settings fields, as before. Omitted for an API key bound to one sub-account." + } + }, + "type": "object" +}
- Changed
update_template3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / profile_id / descriptionPrevious value: -"The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key"New value: +"The sub-account to act on; omitted → your key's sub-account, or the primary sub-account for an account-wide key" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "success": {}, + "template": { + "description": "Message template" + }, + "warnings": { + "description": "Why this template would never be sent as written; empty when it would be. Always sent; absent from an API that predates it." + } + }, + "type": "object" +}
- Added
update_webhook_endpoint - Changed
upload_hitl_keys8 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / backup_dek_ivAdded value: +{ + "description": "v2 envelope: the IV of the recovery wrapping", + "maxLength": 64, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / backup_dek_tagAdded value: +{ + "description": "v2 envelope: the GCM tag of the recovery wrapping", + "maxLength": 64, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / backup_wrapped_dekAdded value: +{ + "description": "v2 envelope: the data key wrapped under the recovery code", + "maxLength": 500, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / dek_ivAdded value: +{ + "description": "v2 envelope: the IV of that wrapping", + "maxLength": 64, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / dek_tagAdded value: +{ + "description": "v2 envelope: the GCM tag of that wrapping", + "maxLength": 64, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / wrapped_dekAdded value: +{ + "description": "v2 envelope: the data key wrapped under the master key", + "maxLength": 500, + "minLength": 1, + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The keypair stored", + "properties": { + "kid": { + "description": "The stored key's id", + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "kid", + "message" + ], + "type": "object" +}
- Changed
validate_proof2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Proof validation result. Returns verification details when valid, or reason/message when invalid. A DELEGATION token answers with `token_type: \"delegation\"` and the `delegation` block instead of `verification`; its status resolves the cascade down to the domain control proof, which neither the status list (it packs each row's own bit) nor an offline signature check can show. Delegation-specific reasons: `unknown_delegation` (no registry record — delegations are minted fail-closed, so this is invalid, not merely unresolvable), `unsupported_version` (a delegation token of a schema major the issuer no longer accepts — 1.x after 2.0; its owner re-issues it), `status_unavailable`, and `identifier_unverifiable` when an `identifier` binding is requested for a delegation.", + "properties": { + "delegation": { + "additionalProperties": {}, + "description": "Delegation claim set, present when a valid delegation token was submitted. The attestation is domain authorization of the artifact — NOT that the artifact is safe, audited or endorsed.", + "properties": { + "control_proof": { + "type": "string" + }, + "delegate": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "issued_at": { + "type": "string" + }, + "principal": { + "type": "string" + }, + "scope": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "principal", + "delegate", + "scope", + "control_proof", + "issued_at", + "expires_at" + ], + "type": "object" + }, + "message": { + "description": "Human-readable message", + "type": "string" + }, + "proof_id": { + "description": "Public proof id (ph_ctl_*), present when the proof is registered", + "type": "string" + }, + "reason": { + "description": "Failure reason: expired, revoked, suspended (a reversible pause — the owner can lift it), invalid (for a token signed by a current registry key this includes a token the issuer has no record of issuing), superseded (the proof was verified again and this token was replaced by a newer one for the same proof — use the newer token; offline verification does not see this), key_revoked (the token names a signing key the issuer has revoked; decided from its `kid` before the signature is checked, so it does not vouch for the token — a genuine holder fetches a re-signed one), identifier_mismatch (the supplied identifier is not what this proof is about), or identifier_unverifiable (the proof's hash is derived from ciphertext, so no identifier can be bound to it)", + "type": "string" + }, + "revoked_at": { + "description": "When the proof was revoked (only present when reason is \"revoked\")", + "type": "string" + }, + "revoked_reason": { + "description": "Reason for revocation (only present when reason is \"revoked\")", + "type": "string" + }, + "suspended_at": { + "description": "When the suspension began — present only with reason `suspended`", + "type": "string" + }, + "token_type": { + "description": "Present ONLY when the submitted token is a delegation (m-delegation-verifier-ref). Its absence means the answer is about a verification/decision proof and the `verification` block applies.", + "type": "string" + }, + "valid": { + "type": "boolean" + }, + "verification": { + "additionalProperties": {}, + "properties": { + "channel": { + "type": "string" + }, + "decision": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "identifier_hash": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "id", + "type", + "channel", + "identifier_hash", + "verified_at", + "expires_at" + ], + "type": "object" + } + }, + "required": [ + "valid" + ], + "type": "object" +}
- Changed
verify_2fa2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The step-up is complete and its grant stored", + "properties": { + "grant_expires_at": { + "description": "When the grant this step-up stored stops being accepted", + "type": "string" + }, + "grant_single_use": { + "description": "Whether the grant is spent by the first act it allows", + "type": "boolean" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "verified_at", + "grant_expires_at", + "grant_single_use" + ], + "type": "object" +}
- Changed
verify_2fa_magic_link2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The step-up is complete", + "properties": { + "action_type": { + "description": "The action the session was started for: one of `TwoFAActionType` for sessions started through this API; admin-console sessions carry internal values.", + "type": "string" + }, + "already_verified": { + "description": "Present (true) when the session had already been verified, by its code or another open of the link; no grant is stored by this call and the grant fields are absent", + "type": "boolean" + }, + "grant_expires_at": { + "description": "When the grant this step-up stored stops being accepted", + "type": "string" + }, + "grant_single_use": { + "description": "Whether the grant is spent by the first act it allows", + "type": "boolean" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "action_type" + ], + "type": "object" +}
- Changed
verify_delegation5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / card / propertyNamesAdded value: +{ + "type": "string" +} - removed
Input schema / properties / delegate / additionalPropertiesRemoved value: -false - removed
Input schema / properties / required_scopesRemoved value: -{ - "description": "Capability scopes the delegation must grant", - "items": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "maxItems": 32, - "minItems": 1, - "type": "array" -} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "attests": { + "description": "When verified: what the delegation attests, in one sentence", + "type": "string" + }, + "cache_age_seconds": { + "description": "How stale the key set is after jwks_stale, in seconds; null when unknown", + "type": [ + "number", + "null" + ] + }, + "delegation": { + "additionalProperties": {}, + "description": "When verified: the verified claims", + "properties": { + "control_proof": { + "type": "string" + }, + "delegate": { + "type": "string" + }, + "delegation_id": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "issued_at": { + "type": "string" + }, + "issuer": { + "type": "string" + }, + "principal": { + "type": "string" + } + }, + "required": [ + "issuer", + "principal", + "delegate", + "control_proof", + "delegation_id", + "issued_at", + "expires_at" + ], + "type": "object" + }, + "disclaimer": { + "description": "When verified: what the verdict does not say", + "type": "string" + }, + "message": { + "description": "When not verified: a readable explanation", + "type": "string" + }, + "outcome": { + "description": "When not verified: invalid (a genuine negative verdict) or unconfirmed (no confident answer right now)", + "type": "string" + }, + "principal_checked": { + "description": "When verified: whether the principal was compared with expected_principal", + "type": "boolean" + }, + "pull_hint": { + "additionalProperties": {}, + "description": "Where to pull a re-signed token after key_revoked", + "properties": { + "handle": { + "type": "string" + }, + "issuer_origin": { + "type": "string" + } + }, + "required": [ + "issuer_origin", + "handle" + ], + "type": "object" + }, + "reason": { + "description": "When not verified: the verifier's failure reason", + "type": "string" + }, + "refresh_hint": { + "additionalProperties": {}, + "description": "How to refresh the key set", + "properties": { + "jwks_uri": { + "type": "string" + }, + "method": { + "type": "string" + } + }, + "required": [ + "jwks_uri", + "method" + ], + "type": "object" + }, + "status_checked": { + "description": "When verified: whether revocation was checked", + "type": "boolean" + }, + "verified": { + "description": "true when the delegation verified; false is a verdict, read reason and outcome", + "type": "boolean" + } + }, + "required": [ + "verified" + ], + "type": "object" +}
- Changed
verify_delegations6 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / items / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / items / items / properties / card / propertyNamesAdded value: +{ + "type": "string" +} - removed
Input schema / properties / items / items / properties / delegate / additionalPropertiesRemoved value: -false - removed
Input schema / properties / items / items / properties / required_scopesRemoved value: -{ - "description": "Capability scopes the delegation must grant", - "items": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "maxItems": 32, - "minItems": 1, - "type": "array" -} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "results": { + "description": "One result per item, in the order the items were given", + "items": { + "anyOf": [ + { + "additionalProperties": {}, + "properties": { + "checked_at": { + "type": "string" + }, + "outcome": { + "const": "confirmed_valid", + "type": "string" + }, + "status_checked": { + "type": "boolean" + }, + "verified": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "outcome", + "verified", + "status_checked", + "checked_at" + ], + "type": "object" + }, + { + "additionalProperties": {}, + "properties": { + "cache_age_seconds": { + "description": "How stale the key set is after jwks_stale, in seconds; null when unknown", + "type": [ + "number", + "null" + ] + }, + "checked_at": { + "type": "string" + }, + "message": { + "type": "string" + }, + "outcome": { + "description": "confirmed_invalid, no_claim_found or unconfirmed", + "type": "string" + }, + "pull_hint": { + "additionalProperties": {}, + "description": "Where to pull a re-signed token after key_revoked", + "properties": { + "handle": { + "type": "string" + }, + "issuer_origin": { + "type": "string" + } + }, + "required": [ + "issuer_origin", + "handle" + ], + "type": "object" + }, + "reason": { + "type": "string" + }, + "refresh_hint": { + "additionalProperties": {}, + "description": "How to refresh the key set", + "properties": { + "jwks_uri": { + "type": "string" + }, + "method": { + "type": "string" + } + }, + "required": [ + "jwks_uri", + "method" + ], + "type": "object" + }, + "verified": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "outcome", + "verified", + "message", + "checked_at" + ], + "type": "object" + } + ] + }, + "type": "array" + } + }, + "required": [ + "results" + ], + "type": "object" +}
- Changed
verify_domain2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The domain after a verification check, by DNS or by an emailed code", + "properties": { + "data": { + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "type": "string" + }, + "dns_mismatch_warning": { + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "type": "boolean" + }, + "oauth_url": { + "type": "string" + }, + "profile_id": { + "type": "string" + }, + "proof_expires_at": { + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "provider_credential_name": { + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "type": "string" + }, + "verification_subtype": { + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" + }, + "message": { + "type": "string" + }, + "renewed": { + "description": "Sent when the call renewed the proof of an already verified domain.", + "type": "boolean" + }, + "verified": { + "description": "Whether control is confirmed after this call.", + "type": "boolean" + } + }, + "required": [ + "data", + "verified", + "message" + ], + "type": "object" +}
- Changed
verify_domain_with_credentials2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "Domain record", + "properties": { + "actual_dns_host": { + "description": "The host serving the zone, when it differs from the provider that verified it.", + "type": "string" + }, + "actual_dns_host_name": { + "type": "string" + }, + "check_count": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "detected_provider": { + "description": "The DNS provider read from the nameservers; `unknown` when none matched.", + "type": "string" + }, + "dns_mismatch_warning": { + "description": "Sent only while `has_dns_mismatch` is true.", + "type": "string" + }, + "dns_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain": { + "type": "string" + }, + "email_sending_enabled": { + "description": "Never sent; read `for_email_sending`. Kept for released SDK types; removed in the next major.", + "type": "boolean" + }, + "email_verification": { + "additionalProperties": {}, + "description": "An email verification of the domain. The code itself is never returned.", + "properties": { + "attempts": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "email_address": { + "type": "string" + }, + "email_prefix": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "last_sent_at": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "email_prefix", + "email_address", + "expires_at", + "attempts" + ], + "type": "object" + }, + "error_message": { + "description": "Why the last check failed.", + "type": "string" + }, + "for_email_sending": { + "type": "boolean" + }, + "for_verification": { + "type": "boolean" + }, + "from_email": { + "type": "string" + }, + "godaddy_connected": { + "description": "Whether a GoDaddy connection is stored for this domain.", + "type": "boolean" + }, + "has_dns_mismatch": { + "type": "boolean" + }, + "has_provider_credentials": { + "description": "Sent only by the add: the account already holds credentials for the detected provider.", + "type": "boolean" + }, + "http_file_content": { + "type": "string" + }, + "http_file_path": { + "type": "string" + }, + "id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "oauth_connected": { + "description": "Whether a Cloudflare connection is stored for this domain.", + "type": "boolean" + }, + "oauth_url": { + "description": "Sent only by the add when Cloudflare sign-in is configured for the detected provider.", + "type": "string" + }, + "profile_id": { + "description": "MongoDB ObjectId", + "type": "string" + }, + "proof_expires_at": { + "description": "When that proof expires — the signed token's own `exp`. `proof_status` stays `active` after this instant (nothing rewrites it), so a client must compare against the clock to tell a live proof from an expired one. Proofs inside 30 days of expiry are renewed automatically while control can still be confirmed. Carried even when `proof_id` is null (a proof that predates the registry still has a signed expiry); null when the domain has no proof, or its proof never stored one.", + "type": [ + "string", + "null" + ] + }, + "proof_id": { + "description": "Public handle of the control proof backing this domain (`ph_ctl_<32 hex>`), resolved through the domain's mirroring asset — the same source `GET /me/assets` reads, so the two surfaces cannot disagree. Null when the domain has no proof, or when its proof predates the registry.", + "type": [ + "string", + "null" + ] + }, + "proof_revoked_reason": { + "description": "Reason the registry recorded, present only while `proof_status` is `revoked`.", + "type": [ + "string", + "null" + ] + }, + "proof_status": { + "description": "Registry status of that proof. A domain row can read `verified` while its proof is `revoked` — the row records that control was once shown, the proof records whether it still stands — so a client showing domain control must render THIS. Null means no registry record, which is NOT a revocation.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Never sent; read `detected_provider`. Kept for released SDK types; removed in the next major.", + "type": "string" + }, + "provider_credential_name": { + "description": "Sent only by the add, with `has_provider_credentials`.", + "type": "string" + }, + "provider_name": { + "type": "string" + }, + "resend": { + "additionalProperties": {}, + "description": "Email-sending setup for a domain. Present once email sending has been set up.", + "properties": { + "dkim_records": { + "items": { + "additionalProperties": {}, + "properties": { + "name": { + "type": "string" + }, + "priority": { + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "purpose": { + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "type", + "name", + "value", + "purpose", + "verified" + ], + "type": "object" + }, + "type": "array" + }, + "domain_id": { + "type": "string" + }, + "last_checked_at": { + "type": "string" + }, + "registered_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "dkim_records" + ], + "type": "object" + }, + "status": { + "description": "Domain verification status. `verifying` while a check runs; `revoking` while the owner's removal or revocation cascade holds the domain; `reverification_required` after a revoked proof, until control is shown again.", + "type": "string" + }, + "supports_api_key": { + "type": "boolean" + }, + "supports_api_token": { + "type": "boolean" + }, + "supports_auto_dns": { + "description": "Whether the detected provider can create the verification record itself.", + "type": "boolean" + }, + "txt_record_name": { + "type": "string" + }, + "txt_record_value": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "verification_method": { + "description": "`auto_dns`, `manual_dns`, `http_file` or `email`.", + "type": "string" + }, + "verification_subtype": { + "description": "How a provider verified the domain: by creating the record, or by confirming ownership without one.", + "type": "string" + }, + "verified_at": { + "type": "string" + }, + "verified_providers": { + "description": "Every provider (or `email`) that has confirmed control.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "domain", + "status", + "detected_provider", + "provider_name", + "supports_auto_dns", + "verification_method", + "for_email_sending", + "for_verification", + "dns_records", + "has_dns_mismatch", + "txt_record_name", + "txt_record_value", + "http_file_path", + "http_file_content", + "oauth_connected", + "godaddy_connected", + "supports_api_token", + "supports_api_key", + "verified_providers", + "check_count", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
verify_email_otp2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "description": "The address is now on the account", + "properties": { + "email": { + "type": "string" + }, + "status": { + "type": "string" + }, + "verified_at": { + "type": "string" + } + }, + "required": [ + "status", + "email", + "verified_at" + ], + "type": "object" +}
- Changed
wait_for_2fa2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "action_type": { + "description": "The action the session was started for: one of `TwoFAActionType` for sessions started through this API; admin-console sessions carry internal values." + }, + "grant_expires_at": { + "description": "When the grant this step-up stored stops being accepted" + }, + "grant_single_use": { + "description": "Whether the grant is spent by the first act it allows" + }, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "session_id": {}, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "verified_at": {}, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_account_creation2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "Authentication channel" + }, + "created_at": {}, + "deep_link": {}, + "email": {}, + "email_error": {}, + "email_sent": {}, + "expires_at": {}, + "id": {}, + "instructions": {}, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "qr_code": { + "description": "Base64-encoded PNG QR code for the deep link" + }, + "qr_text": { + "description": "UTF-8 text QR for terminal/agent rendering" + }, + "sms_code": { + "description": "Short code for SMS-channel reverse-OTP" + }, + "sms_message": {}, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "type": { + "description": "Outcome of an account-session creation. `account_creation` means a new User will be written on verification. `login` indicates the submitted identity matched an existing User and the session will log them in." + }, + "user_id": {}, + "verified_at": {}, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_chat_id_discovery2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "chat_id": {}, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_confirmation2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "created_at": {}, + "hitl_id": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "proof_token": { + "description": "Signed proof of the decision, approval or denial alike, naming who decided (`decided_by`, plus `authorization_id` for an approver); null while pending and for a system denial (`response.channel` is `system`)" + }, + "resends": { + "description": "Every \"Send again\" (`POST /confirmations/{id}/resend`), oldest first, the last 50 kept. Absent from an API that predates it." + }, + "resolved_at": {}, + "response": { + "description": "The decision and its evidence (null while pending)" + }, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_at": { + "description": "When this confirmation will time out" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "updated_at": {}, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_login2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "Authentication channel" + }, + "deep_link": {}, + "expires_at": {}, + "id": {}, + "instructions": {}, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "qr_code": { + "description": "Base64-encoded QR code image" + }, + "qr_text": { + "description": "UTF-8 text representation of the QR code for terminal/agent display" + }, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "type": {}, + "user_id": {}, + "verified_at": {}, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_request2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "action_context": { + "description": "The action the person is asked to authorize; null when the request carries none" + }, + "action_type": { + "description": "Type of action for verification request or authorization" + }, + "assets": {}, + "callback_url": { + "description": "The webhook URL set on the request, if any" + }, + "completed_at": {}, + "computed_state": { + "description": "Additive machine-readable effective state: re-derives expiry from expires_at (never trusts the stored status). BOTH `is_expiring_soon` and `next_action` are role-aware — `next_action.role` says which side this envelope was computed for, and the two fields are consistent within it. Present only on authenticated owner/requester and recipient responses; absent on public/third-party surfaces." + }, + "created_at": {}, + "expires_at": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "partial_ok": {}, + "progress": {}, + "redirect_url": {}, + "reference_id": {}, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "updated_at": {}, + "validity_requirement": { + "description": "Required proof freshness as set on the request (e.g. \"7d\"); null when none was set" + }, + "verification_url": { + "description": "URL for the verification flow" + }, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_session2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "channel": { + "description": "How the person proves the number: `telegram` or `whatsapp` (the bot reads the number from their account), or `sms` (they text a short code from the number to one of ours)." + }, + "created_at": {}, + "id": { + "description": "Session id" + }, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "phone_number": { + "description": "The proven number (once `verified`)" + }, + "proof": { + "description": "Proof token after successful verification" + }, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "verification_id": { + "description": "The verification record created on completion (once `verified`)" + }, + "verified_at": { + "description": "Once `verified`" + }, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
- Changed
wait_for_verification2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {}, + "properties": { + "attempts": {}, + "challenge": { + "description": "Challenge details for verification" + }, + "channel": { + "description": "Channel used for verification. Not yet available — a create or start naming one answers 400 `channel_not_available`: github, google, facebook, x, linkedin, instagram, youtube, tiktok, ethereum, solana, bitcoin, coinbase, kraken." + }, + "created_at": {}, + "external_user_id": {}, + "id": { + "description": "MongoDB ObjectId" + }, + "identifier": { + "description": "The identifier being verified; absent for an identifier-free phone verification, whose number is learned only when the person completes it" + }, + "last_status": { + "description": "On timeout: the last non-terminal status observed, or null when none was" + }, + "max_attempts": {}, + "message": { + "description": "On timeout: what to do next (call the tool again with the same identifier)" + }, + "proof": { + "description": "Proof token after successful verification" + }, + "status": { + "description": "\"pending\" when the wait ran out before a terminal state; otherwise the resource's own status" + }, + "timeout_seconds": { + "description": "On timeout: the wait budget this call was given" + }, + "type": { + "description": "Type of asset being verified. Not yet available — no channel of theirs can be completed, so a create or start answers 400 `channel_not_available`: social, wallet, account." + }, + "updated_at": {}, + "verified_at": {}, + "waited_seconds": { + "description": "On timeout: seconds actually waited" + } + }, + "type": "object" +}
13 tool updates
v1.7.0- Changed
create_profile2 fields changed- added
Input schema / properties / email_themeAdded value: +{ + "description": "Theme of this project's emails", + "enum": [ + "dark", + "light" + ], + "type": "string" +} - added
Input schema / properties / support_emailAdded value: +{ + "description": "Support email this project's messages show", + "format": "email", + "maxLength": 254, + "type": "string" +}
- Removed
delete_profile_template - Changed
delete_template1 field changed- added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +}
- Changed
get_template1 field changed- added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +}
- Removed
list_profile_templates - Changed
list_templates2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +}
- Removed
preview_profile_template - Changed
preview_template1 field changed- added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +}
- Changed
render_template1 field changed- added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +}
- Changed
update_profile2 fields changed- added
Input schema / properties / email_themeAdded value: +{ + "description": "Theme of this project's emails", + "enum": [ + "dark", + "light" + ], + "type": "string" +} - added
Input schema / properties / support_emailAdded value: +{ + "anyOf": [ + { + "anyOf": [ + { + "not": {} + }, + { + "format": "email", + "maxLength": 254, + "type": "string" + } + ], + "description": "Support email this project's messages show" + }, + { + "type": "null" + } + ], + "description": "Support email this project's messages show (null to remove)" +}
- Removed
update_profile_template - Changed
update_settings1 field changed- removed
Input schema / properties / brandingRemoved value: -{ - "additionalProperties": false, - "description": "Branding settings to update", - "properties": { - "business_name": { - "description": "Business name displayed in verifications", - "maxLength": 100, - "type": "string" - }, - "email_theme": { - "description": "Email template theme", - "enum": [ - "dark", - "light" - ], - "type": "string" - }, - "logo_url": { - "anyOf": [ - { - "anyOf": [ - { - "not": {} - }, - { - "format": "uri", - "type": "string" - } - ] - }, - { - "type": "null" - } - ], - "description": "HTTPS URL to business logo" - }, - "primary_color": { - "description": "Primary brand color (hex, e.g. #FF5733)", - "pattern": "^#[0-9A-Fa-f]{6}$", - "type": "string" - }, - "support_email": { - "description": "Support email shown in verification messages", - "format": "email", - "type": "string" - } - }, - "type": "object" -}
- Changed
update_template1 field changed- added
Input schema / properties / profile_idAdded value: +{ + "description": "The sub-account (project) to act on; omitted → your key's project, or the primary project for an account-wide key", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +}
17 tool updates
v1.6.0- Removed
add_challenger - Removed
claim_request_assets - Changed
create_circle1 field changed- added
Input schema / properties / owner_nameAdded value: +{ + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "How this Circle's members know its owner (\"Dad\", \"Giorgi\"). The bots name the owner by it; while it is empty they name nobody — the Circle's name labels the group, never the person. Trimmed by the API; null or an empty value clears it." +}
- Changed
create_confirmation2 fields changed- changed
Input schema / properties / message / descriptionPrevious value: -"Human-readable description of what needs approval"New value: +"The client-encrypted ciphertext envelope as a JSON string (v1 or v2) — NOT the human-readable text. Encrypt the sentence the approver should read; passing it directly is refused with 400 `message_not_encrypted`, because the approval page can only decrypt an envelope." - changed
Input schema / properties / message / maxLengthPrevious value: -2000New value: +10000
- Changed
create_identity_challenge6 fields changed- removed
Input schema / properties / challenger_idRemoved value: -{ - "description": "Enrolled challenger initiating the check", - "pattern": "^[0-9a-fA-F]{24}$", - "type": "string" -} - added
Input schema / properties / circle_idAdded value: +{ + "description": "Circle that holds the member", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - removed
Input schema / properties / hitl_idRemoved value: -{ - "description": "HITL config that holds the challenger", - "pattern": "^[0-9a-fA-F]{24}$", - "type": "string" -} - added
Input schema / properties / member_idAdded value: +{ + "description": "Enrolled Circle member initiating the check", + "pattern": "^[0-9a-fA-F]{24}$", + "type": "string" +} - changed
Input schema / properties / suspicious_channel / descriptionPrevious value: -"Channel the suspicious contact reached the challenger on; defaults to the challenger channel"New value: +"Channel the suspicious contact reached the member on; defaults to the member channel" - changed
Input schema / requiredPrevious value: -[ - "hitl_id", - "challenger_id" -]New value: +[ + "circle_id", + "member_id" +]
- Changed
create_user_request23 fields changed- added
Input schema / properties / action_context / additionalPropertiesAdded value: +false - changed
Input schema / properties / action_context / descriptionPrevious value: -"Additional context about why assets are needed"New value: +"What the recipient is shown about why the assets are needed, e.g. { \"title\": \"Confirm your contact details\" }" - added
Input schema / properties / action_context / propertiesAdded value: +{ + "amount": { + "exclusiveMinimum": 0, + "type": "number" + }, + "currency": { + "maxLength": 10, + "minLength": 1, + "type": "string" + }, + "description": { + "maxLength": 500, + "minLength": 1, + "type": "string" + }, + "entity": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "title": { + "maxLength": 100, + "minLength": 1, + "type": "string" + } +} - changed
Input schema / properties / action_context / typePrevious value: -"string"New value: +"object" - changed
Input schema / properties / action_type / descriptionPrevious value: -"Purpose of the request (default: verification)"New value: +"Purpose of the request (default: verification); custom and confirmation also need an action_context title" - changed
Input schema / properties / action_type / enumPrevious value: -[ - "verification", - "onboarding", - "compliance" -]New value: +[ + "verification", + "2fa", + "login", + "custom", + "confirmation", + "authorization" +] - changed
Input schema / properties / assets / descriptionPrevious value: -"Asset type identifiers to request (e.g. email, phone, identity)"New value: +"Assets to request, e.g. [{ \"type\": \"email\" }, { \"type\": \"phone\", \"required\": false }]" - added
Input schema / properties / assets / items / additionalPropertiesAdded value: +false - added
Input schema / properties / assets / items / propertiesAdded value: +{ + "allowed_channels": { + "description": "Channels the recipient may choose from", + "items": { + "enum": [ + "whatsapp", + "telegram", + "sms", + "email", + "dns", + "http", + "auto", + "github", + "google", + "facebook", + "x", + "linkedin", + "instagram", + "youtube", + "tiktok", + "ethereum", + "solana", + "bitcoin", + "coinbase", + "kraken", + "telegram_bot_token" + ], + "type": "string" + }, + "maxItems": 10, + "type": "array" + }, + "channel": { + "description": "Verification channel to use for this asset", + "enum": [ + "whatsapp", + "telegram", + "sms", + "email", + "dns", + "http", + "auto", + "github", + "google", + "facebook", + "x", + "linkedin", + "instagram", + "youtube", + "tiktok", + "ethereum", + "solana", + "bitcoin", + "coinbase", + "kraken", + "telegram_bot_token" + ], + "type": "string" + }, + "identifier": { + "description": "The exact value to verify (e.g. an email address); omit to let the recipient choose", + "maxLength": 500, + "minLength": 1, + "type": "string" + }, + "required": { + "description": "Whether this asset must be verified (default: true)", + "type": "boolean" + }, + "type": { + "description": "What to verify", + "enum": [ + "phone", + "email", + "domain", + "social", + "wallet", + "telegram_bot" + ], + "type": "string" + } +} - added
Input schema / properties / assets / items / requiredAdded value: +[ + "type" +] - changed
Input schema / properties / assets / items / typePrevious value: -"string"New value: +"object" - changed
Input schema / properties / callback_url / descriptionPrevious value: -"Webhook URL for request status updates"New value: +"HTTPS webhook URL for request status updates" - added
Input schema / properties / callback_url / maxLengthAdded value: +2000 - added
Input schema / properties / callback_url / patternAdded value: +"^https:\\/\\/" - changed
Input schema / properties / expires_in_hours / descriptionPrevious value: -"Hours until request expires (default: 24)"New value: +"Hours until request expires (default: 168, i.e. 7 days)" - added
Input schema / properties / public_profile_id / patternAdded value: +"^[0-9a-fA-F]{24}$" - changed
Input schema / properties / redirect_url / descriptionPrevious value: -"URL to redirect the subject after completing the request"New value: +"HTTPS URL to redirect the subject after completing the request" - added
Input schema / properties / redirect_url / maxLengthAdded value: +2000 - added
Input schema / properties / redirect_url / patternAdded value: +"^https:\\/\\/" - added
Input schema / properties / reference_id / maxLengthAdded value: +255 - added
Input schema / properties / reference_id / minLengthAdded value: +1 - changed
Input schema / properties / validity_requirement / descriptionPrevious value: -"Required validity level for shared assets"New value: +"How recently an existing proof must have been verified for the recipient to reuse it: a number and a unit, h hours, d days, w weeks or m months (30 days), e.g. \"24h\", \"7d\", \"1m\"" - added
Input schema / properties / validity_requirement / patternAdded value: +"^\\d+[hdwm]$"
- Changed
create_verification_request1 field changed- changed
Input schema / properties / expires_in / descriptionPrevious value: -"Request expiry in seconds (default: 86400, max: 604800)"New value: +"Request expiry in seconds (default: 604800, i.e. 7 days; max: 2592000, i.e. 30 days)"
- Added
delete_domain_verification - Changed
export_data2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / export_idAdded value: +{ + "description": "Read this export's status instead of the latest one", + "pattern": "^[a-f0-9]{24}$", + "type": "string" +}
- Removed
invite_challenger - Removed
list_challengers - Removed
remove_challenger - Changed
start_2fa2 fields changed- changed
Input schema / properties / action_type / enumPrevious value: -[ - "api_key_view", - "api_key_create", - "api_key_revoke", - "api_key_regenerate", - "phone_add", - "phone_remove", - "email_add", - "email_remove", - "account_delete" -]New value: +[ + "api_key_view", + "api_key_create", + "api_key_revoke", + "api_key_regenerate", + "phone_add", + "phone_remove", + "email_add", + "email_remove", + "account_delete", + "revocation_bulk", + "domain_remove", + "profile_delete", + "phone_primary", + "email_primary" +] - added
Input schema / properties / targetsAdded value: +{ + "description": "The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the project id; account_delete: your own user id (get_current_user). Leave out for the other action types.", + "items": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "maxItems": 25, + "minItems": 1, + "type": "array" +}
- Changed
start_2fa_for_action3 fields changed- changed
Input schema / properties / action_type / descriptionPrevious value: -"The sensitive action the 2FA grant will authorize. Destructive scopes (api_key_*, account_delete, phone_remove, email_remove, revocation_bulk) are capped at 5 min TTL + forced single-use. Configuration scopes (settings_write, profile_update, templates_write) allow up to 24h TTL with caller-chosen single_use. See config/twoFAPolicy.ts on the backend for the canonical policy."New value: +"The sensitive action the 2FA grant will authorize. Destructive scopes (api_key_*, account_delete, phone_remove, email_remove, phone_primary, email_primary, revocation_bulk, domain_remove, profile_delete) are capped at 5 min TTL + forced single-use. Configuration scopes (settings_write, profile_update, templates_write) allow up to 24h TTL with caller-chosen single_use. See config/twoFAPolicy.ts on the backend for the canonical policy." - changed
Input schema / properties / action_type / enumPrevious value: -[ - "api_key_create", - "api_key_revoke", - "api_key_regenerate", - "api_key_view", - "phone_remove", - "email_remove", - "account_delete", - "revocation_bulk", - "settings_write", - "profile_update", - "templates_write" -]New value: +[ + "api_key_create", + "api_key_revoke", + "api_key_regenerate", + "api_key_view", + "phone_remove", + "email_remove", + "account_delete", + "revocation_bulk", + "domain_remove", + "profile_delete", + "phone_primary", + "email_primary", + "settings_write", + "profile_update", + "templates_write" +] - added
Input schema / properties / targetsAdded value: +{ + "description": "The ids the step-up is FOR — the grant is bound to exactly these and refused for any other request (`reason: target_mismatch`). revocation_bulk: the asset id you will pass to revoke_asset (one code per asset); phone_remove / email_remove: the phone or email record id; domain_remove: the domain id; profile_delete: the project id; account_delete: your own user id (get_current_user). Leave out for the other action types.", + "items": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "maxItems": 25, + "minItems": 1, + "type": "array" +}
- Removed
trigger_drill - Changed
update_circle1 field changed- added
Input schema / properties / owner_nameAdded value: +{ + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "How this Circle's members know its owner (\"Dad\", \"Giorgi\"). The bots name the owner by it; while it is empty they name nobody — the Circle's name labels the group, never the person. Trimmed by the API; null or an empty value clears it." +}
- Changed
update_settings2 fields changed- added
Input schema / properties / proof_expiry_daysAdded value: +{ + "description": "Default proof-token lifetime in days for newly issued proofs", + "maximum": 365, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / webhookAdded value: +{ + "additionalProperties": false, + "description": "Outbound webhook configuration. Deliveries carry an HMAC-SHA256 X-Proof-Signature over \"<X-Proof-Timestamp>.<body>\".", + "properties": { + "events": { + "description": "Subscription patterns: an exact event type, a family wildcard such as \"proof.*\", or \"*\". An empty list means every event.", + "items": { + "type": "string" + }, + "maxItems": 32, + "type": "array" + }, + "rotate_secret": { + "description": "Replace the signing secret and return the new value. The previous value stops verifying immediately.", + "type": "boolean" + }, + "url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2000, + "type": "string" + }, + { + "type": "null" + } + ], + "description": "HTTPS endpoint outbound webhooks are delivered to, at most 2000 characters; null removes it. Private, loopback and link-local addresses are refused." + } + }, + "type": "object" +}
176 tool updates
v1.1.0- First observed
add_challenger - First observed
add_circle_member - First observed
add_circle_member_channel - First observed
add_domain - First observed
add_verification_provider - First observed
cancel_user_request - First observed
cancel_verification_request - First observed
check_domain_credentials - First observed
check_domain_email_status - First observed
check_domain_verification - First observed
check_user_domain_verification - First observed
claim_request_assets - First observed
claim_username - First observed
confirm_domain_email_code - First observed
connect_cloudflare - First observed
connect_dns_provider - First observed
connect_godaddy - First observed
create_account - First observed
create_api_key - First observed
create_authorization - First observed
create_chat_id_discovery - First observed
create_circle - First observed
create_circle_member_drill - First observed
create_confirmation - First observed
create_delegation - First observed
create_dns_credential - First observed
create_hitl - First observed
create_identity_challenge - First observed
create_multi_channel_verification - First observed
create_profile - First observed
create_session - First observed
create_user_request - First observed
create_verification - First observed
create_verification_request - First observed
delete_circle - First observed
delete_dns_credential - First observed
delete_domain - First observed
delete_hitl - First observed
delete_hitl_keys - First observed
delete_profile - First observed
delete_profile_template - First observed
delete_template - First observed
export_authorizations - First observed
export_data - First observed
extend_request - First observed
get_2fa_status - First observed
get_add_email_status - First observed
get_add_phone_status - First observed
get_api_key_usage - First observed
get_asset - First observed
get_authorization - First observed
get_circle - First observed
get_confirmation - First observed
get_confirmation_approval_link - First observed
get_current_user - First observed
get_default_templates - First observed
get_delegation - First observed
get_dns_providers - First observed
get_domain - First observed
get_hitl - First observed
get_hitl_keys - First observed
get_identity_challenge - First observed
get_multi_channel_verification_status - First observed
get_my_profile - First observed
get_platform_summary - First observed
get_profile - First observed
get_profile_assets - First observed
get_proof_status - First observed
get_request_by_reference - First observed
get_request_proofs - First observed
get_self_api_key - First observed
get_session - First observed
get_settings - First observed
get_subscription - First observed
get_template - First observed
get_usage - First observed
get_user_domain_verification_status - First observed
get_verification - First observed
get_verification_request - First observed
get_verified_user - First observed
get_webhook_delivery - First observed
get_webhook_stats - First observed
invite_challenger - First observed
invite_circle_member - First observed
list_api_keys - First observed
list_assets - First observed
list_auth_sessions - First observed
list_authorizations - First observed
list_challengers - First observed
list_circle_member_channels - First observed
list_circle_members - First observed
list_circles - First observed
list_confirmations - First observed
list_delegations - First observed
list_dns_credentials - First observed
list_domains - First observed
list_emails - First observed
list_hitls - First observed
list_incoming_requests - First observed
list_my_requests - First observed
list_phones - First observed
list_profile_templates - First observed
list_profiles - First observed
list_revoked_proofs - First observed
list_templates - First observed
list_verification_requests - First observed
list_verifications - First observed
list_verified_users - First observed
list_webhook_deliveries - First observed
poll_chat_id_discovery - First observed
preview_profile_template - First observed
preview_template - First observed
regenerate_api_key - First observed
remove_challenger - First observed
remove_circle_member - First observed
remove_circle_member_channel - First observed
remove_email - First observed
remove_phone - First observed
render_auth_link - First observed
render_template - First observed
request_hitl_authorization - First observed
resend_domain_email - First observed
resend_email_otp - First observed
resend_verification - First observed
retry_webhook_delivery - First observed
revoke_api_key - First observed
revoke_asset - First observed
revoke_auth_session - First observed
revoke_authorization - First observed
revoke_delegation - First observed
revoke_proof - First observed
search - First observed
send_account_email - First observed
set_primary_email - First observed
set_primary_phone - First observed
set_primary_profile - First observed
setup_domain_email - First observed
share_request_email - First observed
start_2fa - First observed
start_2fa_for_action - First observed
start_add_email - First observed
start_add_phone - First observed
start_domain_email_verification - First observed
start_domain_verification - First observed
start_login - First observed
start_user_domain_verification - First observed
submit_verification_code - First observed
test_verify - First observed
trigger_drill - First observed
trigger_verification - First observed
update_circle - First observed
update_hitl - First observed
update_my_profile - First observed
update_profile - First observed
update_profile_proofs - First observed
update_profile_template - First observed
update_public_proofs - First observed
update_settings - First observed
update_template - First observed
upload_hitl_keys - First observed
validate_proof - First observed
verify_2fa - First observed
verify_2fa_magic_link - First observed
verify_delegation - First observed
verify_delegations - First observed
verify_domain - First observed
verify_domain_with_credentials - First observed
verify_email_otp - First observed
wait_for_2fa - First observed
wait_for_account_creation - First observed
wait_for_chat_id_discovery - First observed
wait_for_confirmation - First observed
wait_for_login - First observed
wait_for_request - First observed
wait_for_session - First observed
wait_for_verification
TDQS
Scored across 179 tools
Several near-identical creation flows coexist: create_verification, create_session, create_multi_channel_verification, create_verification_request, create_user_request, start_domain_verification, start_user_domain_verification, and start_add_phone all appear to start some kind of verification, and an agent must read deeply to pick the right one. Domain checking is likewise split across verify_domain, verify_domain_with_credentials, trigger_verification, check_domain_verification, and check_user_domain_verification, while listing tools (list_verifications, list_verification_requests, list_my_requests, list_incoming_requests) overlap by subject vs creator. Descriptions are rich but the boundaries between tools remain unclear at the set level.
Most names are snake_case verb_noun, but the verb vocabulary is inconsistent for parallel concepts: start_login vs create_account vs create_session, start_add_phone vs create_session, add_domain vs setup_domain_email, plus bare outliers like search and test_verify. Readable, but there is no single predictable convention an agent can rely on to guess a tool name.
179 tools is an extreme surface for a single server — far beyond what an agent can survey, let alone select from reliably. Much of the volume is granular CRUD across a dozen sub-domains (2FA, circles, HITL, delegations, templates, billing, DNS credentials), which should be separate servers or consolidated into fewer parameterized tools.
Coverage is genuinely broad: verification lifecycle, domains, phones, emails, API keys, webhooks, HITL, circles, delegations, billing, templates, login and 2FA flows all have create/read/update/delete-ish operations. Minor gaps exist (e.g. a confirmation resend tool is explicitly noted as absent, and some poll-only flows), but agents can usually work around them.
Maintenance
Related MCP Connectors
Tamper-evident proof creation and verification for AI agents via MCP, A2A, and REST.
Context and control for any AI. Agent identity, scoped access, and proof across tools.
Verified, pay-per-use API tools for AI agents through one authenticated connection.
17 pay-per-call web, finance, legal and onchain tools for AI agents. USDC on Base via x402/MPP.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI agents to retrieve real-time data on wallet DeFi positions, token balances, and NFT holdings across multiple blockchains. It supports hundreds of protocols and provides specialized tools for chain-specific or protocol-specific portfolio analysis.85 npm3MIT
- AlicenseAqualityDmaintenanceEnables AI agents to verify document timestamps and list all recorded proofs on the Verus blockchain using a VerusID. It queries public Verus RPC endpoints to facilitate hash verification without requiring API keys or authentication.347 npmMIT

QuickContract MCPofficial
AlicenseAqualityDmaintenanceEnables AI agents to sign contracts, release escrow, query portfolios, and verify on-chain proofs via QuickContract.175 npmMIT- FlicenseNot gradedqualityDmaintenanceIssues accountable identities for AI agents before they interact with tools, with tools for identity management and receipt export.-