> ## Documentation Index
> Fetch the complete documentation index at: https://gora.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent identities, wallets and recovery

> Separate identity from authority: isolated instances, explicit spending permissions and durable recovery.

# Agent identities, wallets and recovery

One application supports up to **1,000 instances per authenticated owner**.
Each gets `did:gora:testnet:<instance_id>`, independent configuration/state, a
pinned executable and a separate credit payer.

IDs derive from app ID, authenticated owner and nonce. Retrying the same
nonce/configuration returns the same instance; reusing it with different
configuration fails. Other apps/owners get different IDs. Display names are not identities.

Public DID lookup exposes identity/app/version/owner metadata, not prompts,
configuration or state. This is Gora's testnet identifier convention, not a
claim of a standards-registered method or independent on-chain anchoring.

## Public instance API

| Operation | Route |
| - | - |
| Create/list | `POST /apps/{app_id}/instances`, `GET /apps/{app_id}/instances` |
| Read owned instance | `GET /instances/{id}` |
| Configure/pause with current revision | `POST /instances/{id}/config` |
| Invoke / schedule | `POST /instances/{id}/invoke`, `/schedule` |
| State/activity/credits | `GET /instances/{id}/state`, `/activity`, `/credits` |
| Public identity | `GET /v1/dids/{url-encoded-did}` |

Browsers use app-scoped wallet sessions; backends/CLI use private developer
tokens. Body fields cannot impersonate another caller. Create many instances
gradually with stable nonces and respect rate limits; do not launch 1,000 calls at once.

## Identity is not spending authority

| Mechanism | Permission |
| - | - |
| Agent DID | Identifies an instance; no spending by itself |
| App wallet session | Manages the caller's instances and AI/state within one app |
| Explicit signer approval | Authorizes templates from a separate managed testnet wallet |

Base/Solana signers use per-instance/per-chain VM-held keys encrypted at rest
with a separately retained master key. This is **managed custody**, not
threshold signing, an on-chain user-wallet delegation, or independent key management.
Algorand policy vaults are a separate on-chain implementation.

Never use mainnet funds/keys. RPCs are pinned to Base Sepolia `84532` or the full
Solana devnet genesis; changing an endpoint cannot authorize another network.

## Authorize

Read `GET /instances/{id}/signers`. For a wallet-owned agent:

1. `POST /instances/{id}/signers/challenge` with `chain` and `policy`.
2. Verify/show the entire approval; obtain the owner's wallet signature.
3. `POST /instances/{id}/signers` with `challenge_id` and `signature`.

A session token or `consent: true` cannot replace that signature. Developer-owned
server agents can explicitly consent with their private developer credential;
that is not a browser workflow.

Policies bind owner, app, DID and executable and specify:

* Expiry of at most 30 days and a lifetime transaction-count budget.
* Fee ceiling and maximum age of newly signed execution, default two minutes.
* Exact targets/programs/account roles and fixed calldata/instruction prefixes.
* Bounded unsigned arguments: ABI `uint256` on Base, little-endian `u64` on
  Solana. PDA seeds may include the agent's public key.

Templates do not verify a third-party contract's economics. Approved programs
can spend assets in the separate agent wallet through their own code. These
are VM controls; fund only the disposable test amount intended at risk. Base's
ceiling limits signed L2 gas; L1 data charges are additional protocol fees.

The initial policy is immutable. New instructions cannot expand it. Use a new
instance/wallet for different autonomous authority.

## Revoke and recover

`POST /instances/{id}/signers/revoke` with `{"chain":"base"}` blocks new
autonomous signatures. Pausing the instance also blocks them. Neither cancels
transactions already signed/broadcast, nor returns funds automatically.

Recovery requires separate owner approval and works after pause/revoke/expiry:

1. Prepare one exact native/token recovery template, with fixed recipients and
   arguments (`min` equals `max`). Leave native currency for transaction fees.
2. Request `/signers/recovery-challenge` and sign that recovery permission.
3. Submit to `/signers/recover`. It revokes autonomous signing and queues the
   recovery; a new signature may be created within 24 hours of approval.
4. Poll `GET /signers`; `recovery_requests` exposes status/transaction IDs.
   Require confirmation and independently check the recipient balance.

Recovery waits for unresolved signed agent transactions rather than racing
their nonce. Expired Solana transactions, missing receipts or consumed Base
nonces may require operator reconciliation. Pending is not proof of return.

Signed bytes are durable before broadcast. Securely back up the signer DB and
master key together with execution journals. An empty replacement database is
not a recovery procedure; never publish keys or signed journals as diagnostics.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.