World ID · Continuity Track
Left, sections 1–5: Best IDKit Use Case. Right, sections 6–11: Best Use of World ID for Agents. Each section shows its own status.
Withdraw only if you are the same human who opened the account
Before a withdrawal runs, the app asks World ID for a Selfie Check. The server verifies the proof with the Developer Portal and checks that it comes from the same human who opened the account, within the last hour.
IDKit integration
Configured, preflight not run@worldcoin/idkit renders the World ID request. The server signs each request with the RP key (/api/world/selfie-check/context), so the key never reaches the browser.
- App ID
app_63ca83f0764b41c39e7a66c9e16d8bdc- RP ID
rp_d75ba8286d32d7f0- Action
continuity-gate- Environment
production- Protocol
3.0
World ID credential: Selfie Check
Not tested yetTrust event: a withdrawal can't be undone. Before it runs, the product needs to know that the person asking is the same human who opened the account, not someone who stole the session or the device.
| Credential | What it proves | Choice |
|---|---|---|
| Proof of Human (Orb) | Unique human, global | More than needed. Most users would have to visit an Orb. |
| Passport / NFC | Document attributes (age, nationality) | Not relevant here, and collects more than this event needs. |
| Selfie Check | A live face on a phone, with the same nullifier every time for the same person | Chosen, the minimum that is enough. A matching nullifier means it is the same human, and a 1h max_age means the check is recent. |
This opens the real IDKit widget. Scan the QR code with World App. Closing the sheet counts as a cancellation in section 4.
Verify the result on the server
Not tested yetThe widget's result is only forwarded to /api/world/selfie-check/verify. The server checks the protocol version, the credential, the account binding (signal_hash) and the nonce, then calls POST developer.world.org/api/v4/verify/{rp_id}. The withdrawal runs only if the server allows it.
No proof has been verified yet. Run section 2 first.
Alternative path: the action does not run
Not tested yetEvery unsuccessful path is logged here, and none of them unlock the withdrawal. Cancel the World App sheet, get a World App error (credential_unavailable, user_rejected), or send these to the real verify route:
No unsuccessful attempts yet.
Integration debrief
Written- Time to first success
- First integration: about 2.5 days. We started on 2026-09-10, and the portal verified the first Selfie Check proof on 2026-09-12 at 14:21 UTC (HTTP 200). Most of that time went to the protocol version and verify endpoint problems listed below.
- A new app with the same code: minutes. On 2026-09-26 we created a new app, pasted its App ID, RP ID and signing key, and the first proof verified at 05:49 UTC.
- Friction
- Selfie Check can only be issued on World ID 3.0. The 4.0 request type-checks but returns
credential_unavailable. allow_legacy_proofsis required and not documented, and the SDK examples disagree on its value.- The v2 verify endpoint returns
invalid_actionfor every action once RP registration is active. Only v4 works. - IDKit accepts
sandbox, but the verify endpoint has nosandboxenvironment.
- Selfie Check can only be issued on World ID 3.0. The 4.0 request type-checks but returns
- Missing capability / docs
- No page says that
signal_hashequalshash_to_field(signal). sybil_scoreis required by v4 for 4.0 Selfie Check but missing from the SDK types.feature_unavailableandall_verifications_failedare missing from the error reference.- The sandbox has no test users.
- No page says that
- The one improvement with the biggest impact
- State on the Selfie Check credential page which protocol version it can be issued on. That one sentence would have saved most of our time.
The full write-up is in FEEDBACK.md.
An AI agent can't spend your money until you approve it with World ID
Before running a payment, the agent asks for approval. You approve on World's approval page with a fresh proof (mocked in the event sandbox). The backend validates the ID token and checks that the approver is the agent's owner. Only then does the action run.
- 6Agent integration
- 7Approval request
- 8Backend validation
- 9Protected action
- 10Unsuccessful path
- 11Integration debrief
World ID for Agents integration
BlockedThe agent's backend is a confidential OIDC client of the sandbox World ID IdP. It uses the device authorization grant: the agent never needs a browser callback, and every approval requires a fresh World ID proof.
.env.local:- WORLD_AGENT_CLIENT_ID: Not set.
- WORLD_AGENT_CLIENT_SECRET: Not set.
Agent asks the human for approval
Not tested yetValidate the result on the backend
Not tested yetWhen World approves, the backend redeems the device code for an ID token and validates it itself: the RS256 signature against World's JWKS, issuer, audience, expiry, and auth_time inside this attempt. It also checks that the approver is the agent's owner. The browser never gets the token.
Nothing to validate yet. Approve a request in section 7.
Protected agent action
LockedUnsuccessful path: the action does not run
Not tested yetTo test these: click Deny on World's approval page, choose the 30 s window and let it expire, click Cancel request, or send a forged token to the real validator. To test a different human, reset the owner and approve from another World ID.
No unsuccessful attempts yet.
Integration debrief
Written- Time to first success
- One working session on 2026-09-26: reading the guides, registering the client, writing the device flow and JWKS validation. The first approved and validated request ran the agent action at 7:28 PM local time. The only failed attempt before it was approving an old, already-cancelled code by mistake. The backend correctly ignored that one.
- Friction
- The public
/docspage lists no endpoints or fields. The real guides (oidc,step-up) are only in the MCP server, so reading them takes a JSON-RPC client. - Sandbox rejects
http://localhostcallbacks, and a device-only client still has to register an HTTPS redirect URI it never uses. - The device grant ignores
max_age,promptandacr_values. Freshness is implied, so the backend has to checkauth_timeagainst the attempt start itself.
- The public
- Missing capability / docs
- We found no official JS helper for the device grant plus ID-token validation, so we wrote the JWKS check ourselves.
- No binding message. The approval page shows only the user code, not what the agent wants to do. With two requests open, it's easy to approve the wrong one, which happened to us.
- The one improvement with the biggest impact
- Let the agent attach a short, human-readable action description to the device request (like CIBA's
binding_message) and show it on the approval screen, so people approve a specific action, not just a login.