Any language: the three calls
Use Intented from an agent in any language, with a NEAR library and plain HTTP.
The intented package is a convenience. Underneath, a payment is three calls any agent can make: propose on the wallet, POST /api/verdict to the Intented API, then execute on the wallet. You need a NEAR library that can sign function calls (near-api-js, py-near, near-cli-rs or another) and an HTTP client.
Before you start
The agent needs an ed25519 key pair whose public key is on the wallet as a function-call key for propose and execute. Make it with any NEAR tooling, keep the private key on the agent's machine, and paste the public key into the Create page, or Add the agent key on an existing wallet. The wallet itself is the account the key signs for: transactions go from my-agent.intented.testnet to my-agent.intented.testnet.
1. Propose
Build the payment and its action. For a token transfer of 0.001 wNEAR to the vendor:
args_json = {"receiver_id":"intented-vendor.testnet","amount":"1000000000000000000000"}{
"receiver_id": "wrap.testnet",
"method": "ft_transfer",
"args_sha256": "<lowercase hex sha256 of the exact args_json string>",
"deposit": "1",
"nonce": "1793877407816",
"expiry_ms": "1793878307816"
}receiver_idis the token contract; the payee is insideargs_json.depositis in yoctoNEAR, a decimal string.ft_transferneeds exactly"1", which the wallet attaches from its own balance.nonceis unique per payment; the current time in milliseconds works.expiry_msis at most an hour ahead. 15 minutes is a good default.args_sha256must be over the exact string you send asargs_json, byte for byte.
Call propose({ action, args_json }) on the wallet with 30 Tgas and no attached deposit. It returns the proposal_id.
2. Get the verdict
curl -s -X POST "$INTENTED_API_URL/api/verdict" \
-H 'content-type: application/json' \
-d '{"wallet_id":"my-agent.intented.testnet","proposal_id":0,"context":"<what the agent read, verbatim>"}'{
"id": "p_7aebf727ad7a11d7",
"verdict": "ALLOW",
"reason": "The action transfers 0.001 wNEAR to intented-vendor.testnet, which matches …",
"model": "Qwen/Qwen3.8-27B",
"chat_id": "chatcmpl-…",
"signer": "0x835ab53d20294ef795906dff21ae4c045336aa26",
"signature": "0x…",
"req_bytes": "<base64>",
"resp_bytes": "<base64>"
}The API reads the action from the chain, not from your request, so you can't ask it to judge something other than what you proposed. context is at most 20,000 characters. See the API reference for every error.
3. Execute
Call execute on the wallet with 300 Tgas and no attached deposit:
{ "proposal_id": 0, "req_bytes": "<from the verdict>", "resp_bytes": "<from the verdict>", "sig_65": "<signature from the verdict>" }Send it for a DENY too. The wallet refuses with "verdict is not ALLOW", and that refusal is the on-chain record. A successful execute makes the transfer; a refused one moves nothing. The errors reference lists every refusal.
4. Report it (optional)
curl -s -X POST "$INTENTED_API_URL/api/executed" \
-H 'content-type: application/json' \
-d '{"wallet_id":"my-agent.intented.testnet","proposal_id":0,"near_tx_hash":"<execute tx hash>"}'The API looks the transaction up on-chain and links it on the payment's receipt. Without it, the receipt still shows the verdict and the proposal's status, read from the wallet.
A working implementation
The TypeScript in the repo does exactly these steps: agent/src/wallet.ts builds the action, and agent/src/pay.ts runs propose, verdict, execute and report.