Get an X-EGO verification link
xego_request_proof_urlREQUIRES a one-time EUR 3 Planetary ID held by YOUR END USER - without it every call returns valid:false. Tell the human this BEFORE sending them to the link: if they do not have one yet, the verification page sells it in the same flow — it is not a separate signup.
Returns the URL the agent sends a human user to, so they can
prove they are human. On that page the user verifies with a
passkey (fingerprint / Face ID) and receives a short-lived signed
token (JWT). The agent then verifies it with xego_verify_proof
(no action) or xego_verify_action (with action).
ASK FIRST what is being approved, then bind it. Two ways, and the choice matters more than anything else on this tool:
call— USE THIS WHENEVER A TOOL WILL RUN. Pass the exact call { v:1, tool, target, args, policy? } you are about to execute. The human approves the call itself, field by field.action— a sentence, for approvals where nothing executes (a consent, a statement). It seals what the human READ, and a well-written sentence can hide what actually happens.
Both may be passed together: the sentence is what the human
reads, the call is what gets compared. Either one means the
token MUST be verified with xego_verify_action; with neither,
use xego_verify_proof. The returned binding field says which.
For emails: recipient and content; compose the final wording and get the user's OK before calling.
This tool performs NO verification itself — it only prepares the link. No personal data is transferred.
THE USER DOES NOT HAVE TO COPY THE TOKEN. Pass redirect_uri (or return_origin) and the page delivers the token to you after the passkey tap — the human part (fingerprint / Face ID) is unchanged. redirect_uri is the recommended channel: it is the only one that survives a user who is still buying a Planetary ID in the same pass. The returned token_delivery field tells you what to expect. With neither parameter the current behaviour stays: the token is shown on the page and the human hands it to you.
Verification requires a paid Planetary ID (one-time EUR 3, ~2 min, passkey on the user's own device — biometrics never leave it). If the user does not have one yet, the verification page offers it there. Send the user to the returned verification_url; if they come back without a token, they still need the ID — verification then fails with planetary_id_required and a registration_url.
Args:
audience (string): the domain of the service requesting verification (domain or URL — normalized to a bare hostname).
call (object, RECOMMENDED when a tool will run): the exact call { v:1, tool, target, args, policy? }. Rendered field by field on the page; the token seals it. Verify with expected_call built from YOUR OWN parsed parameters.
action (string, OPTIONAL fallback): a sentence describing the approval, for cases where nothing executes. The user sees it and the token is valid only for it — pass the same string as expected_action to xego_verify_action.
redirect_uri (string, OPTIONAL): where to navigate with the token in the fragment. Only https on x-ego.com/*.x-ego.com or http(s) on loopback; no fragment. The target must be HTML that reads location.hash — a fragment is never sent in an HTTP request.
return_origin (string, OPTIONAL): origin for postMessage into window.opener, same allowlist. Popups only.
state (string, OPTIONAL): correlation value, echoed back verbatim. [A-Za-z0-9._~-], max 256 chars.
Returns (JSON): { "verification_url": string, // link for the user "audience": string, // normalized bare hostname — pass // this exact value as // expected_audience to the verify tool "action": string, // only if one was given — pass the // same string as expected_action "token_delivery": object, // mode: redirect | post_message | // manual — how the token comes back "state": string, // only if one was given — echoed // back verbatim with the token too "instructions": string, // what to do with the link "next_step": string, // next step — follow it "if_user_has_no_planetary_id": object // status planetary_id_required: // registration_url, explanation, next_step }
Errors: invalid_audience (audience cannot be normalized), invalid_redirect_uri / invalid_return_origin (target outside the allowlist, or a redirect_uri carrying a fragment), invalid_state (outside the allowed character set or length). All are free.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| call | No | RECOMMENDED whenever a tool will actually run. The exact call the human is approving: { v: 1, tool, target, args, policy? }. The verification page renders it field by field, the human taps the passkey against THAT, and the token seals it (claim cal). The executor then verifies with xego_verify_action and expected_call built from its OWN parsed parameters — never from what another party says the call is, or it is only comparing a claim with itself. Build it from the same values you are about to execute. Decimal numbers are rejected (call_unsafe_number) — use integers in minor units or strings. | |
| state | No | OPTIONAL. An opaque correlation value that lets you recognize your own request; it is echoed back verbatim (as a state field in postMessage, as &state= in the redirect fragment). Character set [A-Za-z0-9._~-]. X-EGO neither stores nor interprets it. Recommended with return_origin, where no other binding to the request exists; with redirect_uri you can carry the binding in the target's query instead. | |
| action | No | FALLBACK binding, for approvals where nothing is executed (a statement, a consent, a message being sent). A human-readable description of what the user is approving (e.g. 'Transfer EUR 500 to account 123456789/0100'). The user SEES this exact text before the passkey tap and the token is valid ONLY for it (claim act = SHA-256 of the text). Prefer `call` when a tool will run: a sentence seals what the human READ, not what then executes. May be combined with `call` — then the sentence is what the human reads and the call is what is checked. Tokens carrying either MUST be verified with xego_verify_action, not xego_verify_proof; pass the BIT-FOR-BIT identical string as expected_action (action_mismatch on any difference). | |
| audience | Yes | The domain of the service requesting verification (e.g. 'forum.example.com'). A URL is accepted too ('https://forum.example.com/path') — it is always normalized to a bare lowercase hostname (max 253 chars). It determines who the proof will be valid for. The pairwise ID differs per audience, so services cannot track a user across each other. | |
| redirect_uri | No | OPTIONAL automatic token hand-off. An absolute URL the verification page navigates to on success, with the token in the URL FRAGMENT (#token=...). The user copies nothing. Only https on x-ego.com/*.x-ego.com or http(s) on loopback (localhost, 127.0.0.1, ::1) is allowed; any other target is rejected. Path and query are preserved — put your own correlation value there. It MUST NOT carry a fragment (that is where the token goes). NOTE: a fragment is never sent in an HTTP request — the target must serve HTML that reads it in the browser (location.hash); a bare server endpoint will not see the token. This is the ONLY channel that survives a user who buys a Planetary ID mid-flow. | |
| return_origin | No | OPTIONAL automatic token hand-off into the window that opened the verification page: postMessage({type:'xego_token', token, audience, pairwise_id, state}) at the EXACT origin (never '*'). Same allowlist as redirect_uri. Use only when you opened the page as a popup via window.open. It does not work when the user buys a Planetary ID along the way — checkout severs the link to the opener window; use redirect_uri for that case. |