Documentation
Guides and reference for OutLayer verifiable compute and agent custody.
Docs navigation
Personal Account Binding
Let an agent act as a named account you already own, while you keep the keys.
For the calls themselves — every endpoint, its arguments, and how to read a refusal — see the Binding API reference.
Bind Your Own Account#
By default an agent acts as its own implicit account. Binding lets it act as a named account you already own —alice.near instead of a 64-character hex string — while you keep your keys and the agent gets only what your policy allows.
You install a small wallet contract on your own account and add the agent's executor to its extension set. That contract is an extra door, not a new owner: your own keys keep signing directly, and you can shut the door at any time with one transaction. Nothing here can be done without your signature.
Installation is nearly free. The contract is published once, network-wide, as a global contract, and your account only references it by hash — you never pay to store the ~278 KB of code. Your setup transaction costs a little state, two 1-yoctoNEAR markers and gas. Under 0.1 NEAR is plenty.
Step 1 — record the binding
This returns the executor_account_id you are about to authorize. It records a relationship and authorizes nothing: the status stays pending until the executor is actually in your account's extension set.
curl -s -X PUT -H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"asset_account_id":"alice.near","kind":"personal_account"}' \
"https://api.outlayer.ai/wallet/v1/binding"Step 2 — get the transaction to sign
OutLayer assembles the payload; you sign it yourself. One transaction, three actions: reference the contract by hash, initialise it, and add the executor.
curl -s -H "Authorization: Bearer $API_KEY" \
"https://api.outlayer.ai/wallet/v1/binding/setup?kind=personal_account"Or let the person sign it in a browser. An agent has no way to sign for somebody else's account, so this is the one step it must hand over. Send the owner to https://app.outlayer.ai/wallet/connect?key=<the agent's wk_> — the page reads the pending binding, shows every action in the transaction before anything is signed, refuses to proceed if the connected wallet is not the account being bound, and links straight to the policy editor once it is active. No CLI, no copied payloads.
Not every wallet can sign it. Referencing the contract by hash is the UseGlobalContract action (NEP-591), and most NEAR wallets still have no branch for it — they refuse with something opaque, or, in MyNearWallet's case, open a sign page that never resolves. Intear Wallet signs it on both networks and is what the browser page recommends; the near-cli connector works too. Signing the payload yourself with a NEAR key sidesteps the question entirely.
Use an account with no contract on it. The kit answers 409 if your account already runs one, and that refusal is deliberate: deploying over an existing contract does not clear its state. The usual victim would be a 2FA or multisig wallet contract. Your tokens, NFTs and staking are never at risk from the deploy itself — they live in other contracts — but a wrecked contract on your account is not something we will help you sign.
Step 3 — confirm it went live
curl -s -H "Authorization: Bearer $API_KEY" \
"https://api.outlayer.ai/wallet/v1/binding"{
"binding_status": "active",
"asset_account_id": "alice.near",
"executor_account_id": "9c3c9e10...",
"gas_balance": "120000000000000000000000",
"gas_balance_low": false
}The executor pays gas for every call it makes on your behalf, so keep a little NEAR on it.gas_balance_low tells you when to top it up, and abinding.gas_low webhook fires once when it crosses the line.
What the agent can do now
- Spend from your account through your policy — the same whitelists, per-transaction caps and velocity limits as any custody wallet.
- Send email as
[email protected]instead of from a hex address. - Nothing else. Rewiring the account (adding or removing extensions, changing signature mode) is refused outright, whatever the policy says.
Your limits are read from what the request actually does, not from what it looks like on the outside. A single request can carry several transfers and token moves at once; every recipient, every amount, and every refund destination inside it is checked against your rules before anything is signed.
Three rules your policy must carry, or the lane is dead. After the inside of a request is checked, the call itself faces your ordinary rules — and on this lane that call is a call, goes to your bound account, and is denominated in NEAR whatever token moves inside it. So transaction_types must list call — a policy of ["transfer"] describes exactly what you want and refuses the only route that does it. An address whitelist must list your own bound account alongside the payees, or every call is refused with Address 'alice.near' is not in whitelist — the account you never listed as a destination. And allowed_tokens must include native (or "*"), or native transfers stop even when what moves inside is a token you did allow. Use mode: "none" if you do not want an address filter at all. Each of those three refusals names which one it is. And whatever NEAR that outer call attaches is measured against your native limits like any other spend — only the 1 yoctoNEAR marker a payable method demands is left out, because it proves a key rather than paying anyone.
Your policy is the only limit here. A leased account has an on-chain spend grant behind it; your own account does not. A binding with no policy on it means the agent can move everything in that account — set the policy before you sign, not after.
Turning it off
Remove the executor from your account's extension set — one transaction, signed by you, no permission needed from us. The lane stops within five seconds — a permission we checked a moment ago is cached for that long, and nothing else outlives the fact. DELETE /wallet/v1/binding ends OutLayer's side of it and cancels any approvals still waiting on that account. Redeploying or removing the contract works too.
The other mode: leased accounts#
Everything above is kind: "personal_account" — your account, your keys, your policy. There is a second mode, hos_lease, where a partner provisions the account and lends it to an agent under an on-chain spend grant. Nobody signs a setup transaction there, the grant is a second ceiling above your policy, and the request shape it accepts is narrower.
It has its own page: Agent Connect.
Running under the bound name#
A binding is a capability, not a rename. By default the agent's calls still run under its own name — a WASI guest sees its own wallet account in NEAR_SENDER_ID, exactly as before any binding existed, because connectors derive real things from that name.
The agent asks for the bound name per call, and it works the same on both doors — over HTTPS and from a transaction — so one module answers the same question about who it is however it was started:
curl -s -X POST -H "Content-Type: application/json" \
-H "X-Payment-Key: $PAYMENT_KEY" \
-d '{"input":{"operation":"send"}, "use_bound_identity": true}' \
"https://api.outlayer.ai/call/connectors.outlayer.near/near-email"On chain the same flag goes in params of request_execution. There the binding is matched by the caller of the transaction — the wallet's own implicit account — so the transaction has to be sent by the wallet itself.
Billing never follows the name: the call is still paid by the agent's key, and the earnings ledger records the payer rather than the borrowed identity. Asked for and unavailable is a refusal, never a quiet fallback to the agent's own name.
Ending it#
Remove the executor from the account's extension set — one transaction, signed by the owner, no permission needed from us. The lane stops within five seconds — an allow we checked a moment ago is cached for that long, and a denial is never cached at all. DELETE /wallet/v1/binding ends OutLayer's side of it and cancels approvals still waiting on that account.
See also Agent Custody for wallets, policies and the rest of the API.