World ID delegation

World ID personhood on Thirdfy delegation. Organization enrollment, single-use deposit receipts, and the CLI and MCP commands that call them.

World ID on Thirdfy is a personhood check attached to delegation. It is not a Gator signature and it is not a login. World ID issues the proof. Thirdfy stores the organization lock and, when requested, a single-use deposit receipt.

Protocol background: World ID and IDKit.

EarnOrg calls these routes for organization security. The same HTTP surface is available to CLI and MCP callers with a Thirdfy session.

Two proofs, one action

Both proofs use the action delegate-org:{orgId}.

ProofSignalWhat complete does
Organization enrollmentOrganization idLocks the first verified World ID nullifier to the org. A different person fails with WORLD_ID_ORG_NULLIFIER_MISMATCH.
Deposit receiptdeposit:{challengeId}Compares the nullifier to that org lock. Does not rotate the organization row. Returns a receipt id.

begin returns an IDKit request: action, appId, environment, signal, and signed rpContext (rp_id, nonce, created_at, expires_at, signature). The client runs IDKit with that payload, with user presence required, then posts the proof object to complete.

Default chain is Base (8453).

Organization enrollment

StepMethodPath
BeginPOST/api/v1/agent/delegation/world-id/org/begin
CompletePOST/api/v1/agent/delegation/world-id/org/complete
CheckGET/api/v1/agent/delegation/world-id/org/check

Begin body: orgId, optional chainId.

Complete body: orgId, proof (the IDKit result), optional chainId.

Check query: orgId, optional chainId. The response data.worldId reports status for that organization.

Agent-scoped begin and complete also exist for a hosted agent key:

StepMethodPath
BeginPOST/api/v1/agent/delegation/world-id/begin
CompletePOST/api/v1/agent/delegation/world-id/complete

Those bodies take agentKey instead of orgId. EarnOrg organization security uses the org routes above.

Deposit receipts

StepMethodPath
BeginPOST/api/v1/agent/delegation/world-id/deposit/begin
CompletePOST/api/v1/agent/delegation/world-id/deposit/complete
ConsumePOST/api/v1/agent/delegation/world-id/deposit/consume

Begin body:

FieldRequiredNotes
orgIdYesOrganization the receipt belongs to
depositSignalNoMust be deposit:… when set. Thirdfy mints one when omitted.
runtimeIdNoEarnOrg runtime the deposit is for
amountUsdNoIntended transfer amount
destinationAddressNoAgent wallet that should receive the funds
chainIdNoDefaults to 8453
idempotencyKeyNoCaller retry key

Complete body: orgId and proof. Success returns a receipt id. The organization enrollment row stays as it was.

Consume body: orgId and receiptId, plus optional runtimeId and amountUsd. A receipt can be consumed once. A second consume fails with WORLD_ID_DEPOSIT_RECEIPT_ALREADY_USED.

CLI

Current @thirdfy/agent-cli commands (owner session, not the agent API key alone):

thirdfy-agent delegation world-id-begin --agent-key <key> --chain-id 8453 --json

thirdfy-agent delegation world-id-complete --agent-key <key> --proof '<idkit-json>' --json

thirdfy-agent delegation world-id-deposit-begin \
  --org-id <uuid> \
  --runtime-id <uuid> \
  --amount-usd 25 \
  --destination-address 0x... \
  --json

thirdfy-agent delegation world-id-deposit-complete --org-id <uuid> --proof '<idkit-json>' --json

Deposit begin and complete post to the deposit routes. They do not call organization enrollment complete.

MCP

ToolRoute
delegationWorldIdBeginPOST /api/v1/agent/delegation/world-id/begin
delegationWorldIdCompletePOST /api/v1/agent/delegation/world-id/complete
delegationWorldIdDepositBeginPOST /api/v1/agent/delegation/world-id/deposit/begin
delegationWorldIdDepositCompletePOST /api/v1/agent/delegation/world-id/deposit/complete