TESTNET ONLY. Xahau testnet (network ID 21338), test XAH from the public faucet. No real money. Nothing here is a mainnet service, an offer, or financial advice. The API may be offline at any time.

HOOKAGENT desk: public spec v1

Version 2026-10-30. How an outside agent pays for an AI job and an outside provider gets paid for doing it, through a locked escrow desk on the Xahau testnet.

1. The pieces

ThingValue
Desk account (locked: master key off, regular key blackholed, the hook can never change)r33bVFZRF5w3VNSD62QusxgTfuY3v9ao95
NetworkXahau testnet, node wss://xahau-test.net, network ID 21338, explorer https://explorer.xahau-test.net/tx/<hash>, faucet POST https://xahau-test.net/accounts {"destination": "r..."}
Proof worker API (HTTPS)https://hookagent-desk-api.xah-8b4.workers.dev
Worker account (the only account that can pay a provider, or return funds for a bad proof)r3pAGLrgBHgeCBVCnyhuTsZyq1oWc2CvDs
Proofs accepted (v1)TOPLOC only. v1 checks the TOPLOC proof only; TEE support is planned after a real TDX hardware test. A job that requires TEE is returned to the agent right away.
Models accepted (v1)HuggingFaceTB/SmolLM2-135M-Instruct at revision 12fd25f77366fa6b3b4b768ec3050bf629380bac (greedy decoding, 1-64 new tokens, prompt 1-1000 characters)
Desk limitsSmallest job 0.1 XAH. Deadline at most 1 hour after opening. No release fee (cut is 0). The desk pays network fees for its own payouts from a separate fee balance; agent money is never used for fees.

How it works: the agent prepays the desk and names its provider(s). The agent opens a job: an amount held for one named provider until a deadline, plus a fingerprint of the job description. The agent hands the job description to the API. The provider runs the job, builds a TOPLOC proof and sends it, signed, to the API. The worker re-checks the proof. If it is good, the worker tells the desk to pay the provider. If it is bad, the money goes back to the agent. If nothing happens by the deadline, anyone can tell the desk to return the money to the agent. Every payout carries a public receipt.

2. Encoding rules

All desk actions are ordinary Xahau transactions sent to the desk account, carrying HookParameters. Each parameter name is the ASCII name as uppercase hex. Each value is uppercase hex:

Hook transactions cost more than plain payments. Ask the node for the fee with the fee command, passing your unsigned tx_blob, then pay a bit more (for example 1.5x). Load the binary field definitions from the node's server_definitions so the hook fields encode. The @transia/xrpl + @transia/ripple-binary-codec libraries do this.

3. Agent: fund the desk

Send a Payment of XAH to the desk. On your first funding you must name 1 to 3 providers.

ParameterValue
PRV1-3 provider accounts, concatenated (20, 40 or 60 bytes)required on first funding; later fundings may change the list
ISSaccountoptional: a separate account allowed to open jobs for you. Without it, you open your own jobs.
PJCamountoptional per-job cap (0 = none). A release over it is turned into a return.
PDCamountoptional per-day cap on released money (0 = none)

The hook answers desk: funded. Your unused balance can be taken back at any time: Invoke with ACT=05 (withdraw), signed by the agent.

4. Agent: open a job

Job description (JSON, exactly these 4 fields):

{"model":"HuggingFaceTB/SmolLM2-135M-Instruct","revision":"12fd25f77366fa6b3b4b768ec3050bf629380bac","prompt":"In one sentence, what is an escrow?","max_new_tokens":24}

jobHash = the first 32 bytes of SHA-512 over the UTF-8 bytes of the job description, written with its keys sorted alphabetically and no spaces ({"max_new_tokens":24,"model":"...","prompt":"...","revision":"..."}), as uppercase hex.

Send an Invoke to the desk, signed by you (or your ISS account):

ParameterValue
ACT01
AGTaccount: the agent whose prepaid balance pays
PROVaccount: the provider (must be on the agent's PRV list)
AMTamount (at least 0.1 XAH, within your prepaid balance)
DLtime: the deadline, later than now and at most 1 hour ahead
PRFbyte: required proofs. 02 = TOPLOC (the only value v1 accepts). 01 = TEE and 03 = TEE+TOPLOC are returned to you at once.
JOBthe 32-byte jobHash

If it is accepted (tesSUCCESS), the desk hook's HookReturnString in the transaction metadata (meta.HookExecutions[].HookExecution.HookReturnString) is the 32-byte job reference (cref), as 64 hex characters. Keep it. The amount is now held for the provider until the deadline. If it is refused (tecHOOK_REJECTED), the return string is a readable reason. New jobs are refused while the desk's fee balance is at its floor.

5. Agent: hand the job to the provider

POST /job
{"cref":"<64 hex>","jobSpec":{"model":"...","revision":"...","prompt":"...","max_new_tokens":24}}

The API checks that the job is open on the desk, that the description passes the allow-list, and that it hashes to the on-chain jobHash. Anyone can make this call, because only the matching description is accepted. Job descriptions are public on testnet. Do not put secrets in prompts. If the model is not allowed, the hand-off is refused (422) and the job can never be paid. Take the money back with the timeout return after the deadline.

6. Provider: find, check and run the job

GET /job/<cref>
-> {"job":{"cref","desk","agent","provider","amountDrops","deadlineRippleTime","deadlineISO","requiredProofs","jobHash","state"},"jobSpec":{...}|null,"handedOff":true|false}

To find jobs naming you, subscribe to the desk account on the public node and look for successful Invoke transactions with ACT=01 and PROV = your account (cref = their HookReturnString). Before you work, check: job.provider is you, state is open, there is enough time before the deadline, and jobHash(jobSpec) equals job.jobHash.

TOPLOC how-to (CPU is fine). Install: pip install torch transformers toploc==0.1.6. Run the reference prover toploc_prove.py. The worker re-runs one forward pass and checks these exact rules:

  1. Load the model at the pinned revision in float32.
  2. The prompt is one user message in the model's own chat template, with add_generation_prompt=True.
  3. Use greedy decoding (do_sample=False) for up to max_new_tokens. Every output token must be the model's top choice.
  4. Activations: the last hidden layer. Use all prompt rows (prefill) plus one row per decode step, each cast to bfloat16.
  5. Build the proof with toploc.build_proofs_base64(acts, decode_batching_size=8, topk=128, skip_prefill=False). Other topk or batching values are refused.
  6. The output text is tokenizer.decode(output_ids, skip_special_tokens=True).

7. Provider: submit the proof

POST /proof
{"cref":"<64 hex>",
 "payload":"{\"output\":\"...\",\"toploc\":{\"output_ids\":[...],\"proofs\":[\"base64...\"],\"topk\":128,\"dbs\":8}}",
 "publicKey":"<your 33-byte public key, 66 hex>",
 "signature":"<hex>"}

8. Timeout return (always available)

After the deadline, anyone can send an Invoke with ACT=04 and CREF = the job reference. The held amount goes back to the agent. This works on chain even if the API is offline, so an agent's money is never stuck.

9. Receipts

Every payout from the desk (release, return, cap block) is a Payment from the desk account carrying a memo of type HKD/R1. Decode it with:

GET /receipt/<payout tx hash>
-> {"receipt":{"status":"released|returned|blocked_by_cap","reason":"none|timeout|bad_proofs|per_job_cap|per_day_cap|payout_failed_timeout",
     "proofTypes":["toploc"],"jobHash","challengeRef","amountDrops","timestamp","deskAccount","paidTo","yellow":{"room":"","channel":""}},
    "amountPaidDrops","result","validated"}

challengeRef is the cref. The Yellow fields are always empty (no next-hop layer is used).

10. Limits and abuse rules

Body sizePOST /job 16 KB, POST /proof 256 KB (413 above)
Rate limitsAll requests (GET and POST): 30 requests/min per IP (IPv6 per /64). 10 job posts and 6 proof posts per min per IP. 20 proof submissions per hour per provider. The whole API takes 120 requests/min, 30 job posts and 20 proof posts per min (429 above).
Allow-listThe model and revision above only. 1-64 new tokens. Prompt 1-1000 characters.
Desk checkOnly jobs held on this desk are accepted (404 otherwise).
SignatureProofs must be signed by the job's provider (403 otherwise).
TimingProofs are refused with less than 45 s before the deadline. One check runs at a time (503 "busy" if the queue is full; retry).

11. Endpoints, errors, retries

GET  /health           GET /info           POST /job           GET /job/<cref>
POST /proof            GET /receipt/<txhash>

12. Honest limits of this testnet setup