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

# Agent Wallets for Automated Trading

> Authorize a dedicated API wallet to trade for a master account while keeping the master private key offline, with expiry, monitoring, rotation, and revocation controls.

An **agent wallet** is a separate signing wallet authorized to submit selected trading actions on behalf of a master account. It lets an automated strategy place and manage orders without keeping the master account's private key online.

Agent wallets are designed for delegated execution, not custody. Keep the master key offline, give each strategy or environment its own agent identity, and place deterministic validation between any AI-generated intent and the signer.

<Warning>
  An approved agent can submit real state-changing requests. Treat its private key as a production credential, limit its lifetime and operational scope in your application, and maintain an independent revocation path.
</Warning>

## Capabilities and limits

| Property             | Behavior                                                                                                        |
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
| Supported execution  | Agents can submit orders, cancellations, modifications, and TP/SL requests on behalf of the master account      |
| Master-key isolation | The master key is used to authorize or revoke an agent, then can remain offline during normal automated trading |
| Anonymous slots      | Up to 1 anonymous agent per master account                                                                      |
| Named slots          | Up to 3 named agents per master account                                                                         |
| Expiry               | `validUntil` is a Unix millisecond timestamp; `0` means no automatic expiry                                     |
| Renewal              | Re-approving an already authorized address refreshes its expiry without consuming another slot                  |
| Name replacement     | Approving a named agent with an existing name replaces the previous entry for that name                         |
| Administration       | Only the master account can approve or revoke agents                                                            |
| Inventory query      | `userAgents` returns both active and expired agent records for auditing and cleanup                             |

## Recommended lifecycle

<Steps>
  <Step title="Create a dedicated wallet">
    Generate a new wallet for one strategy, service, or environment. Store its private key in a KMS, HSM, or secrets manager and expose only a narrow signing interface to the trading service.

    ```python theme={"system"}
    from eth_account import Account

    agent = Account.create()
    agent_address = agent.address

    # Store agent.key in a secure secret store.
    # Never print it, send it to an LLM, or commit it to source control.
    print(agent_address)
    ```
  </Step>

  <Step title="Approve it from the master account">
    Submit [`approveAgent`](/exchange/approve-agent), signed by the master account. Prefer a descriptive `agentName` and a finite `validUntil` for production automation.

    ```json theme={"system"}
    {
      "action": {
        "type": "approveAgent",
        "agentAddress": "0xabc0000000000000000000000000000000000001",
        "agentName": "market-maker-prod",
        "validUntil": 1893456000000
      },
      "signature": {
        "r": "0x...",
        "s": "0x...",
        "v": 28
      },
      "nonce": 1782259200123
    }
    ```
  </Step>

  <Step title="Verify the authorization">
    Query [`userAgents`](/info/user-agents) with the master account ID and confirm the returned address, name, expiry, and slot type before enabling the signer.

    ```json theme={"system"}
    {
      "type": "userAgents",
      "accountId": "5"
    }
    ```
  </Step>

  <Step title="Sign only validated actions">
    The strategy or model should produce an unsigned intent. A deterministic policy layer validates the action, applies risk controls, assigns a unique nonce, and sends the canonical payload to the agent signer.
  </Step>

  <Step title="Monitor and reconcile">
    Track open orders and fills through the [Read API](/info/overview) and private [WebSocket channels](/websocket/overview). Stop submitting new writes when authorization is near expiry, state is stale, or reconciliation falls behind.
  </Step>

  <Step title="Rotate or revoke">
    Approve the replacement wallet, verify it, switch the signer, and then call [`revokeAgent`](/exchange/revoke-agent) for the old address. Maintain a separate operator-controlled kill switch that can revoke the active agent without relying on the strategy process.
  </Step>
</Steps>

## Agent execution envelope

Every state-changing operation uses `POST /exchange` and follows the standard signing process documented in [Authentication](/guide/authentication). The nonce must be unique for the **agent signing address**, not merely for the master account.

When using the documented proxy or vault flow, include the target `vaultAddress` at the top level. The server verifies that the recovered signer is authorized for that target.

```json theme={"system"}
{
  "action": {
    "type": "order",
    "orders": [
      {
        "a": 1,
        "b": true,
        "p": "50",
        "s": "1",
        "r": false,
        "t": {
          "limit": {
            "tif": "Gtc"
          }
        }
      }
    ],
    "grouping": "na"
  },
  "signature": {
    "r": "0x...",
    "s": "0x...",
    "v": 27
  },
  "nonce": 1782259200456,
  "vaultAddress": "0xmaster000000000000000000000000000000000001"
}
```

<Note>
  Build and sign the exact action shape defined by the relevant Write API page. Do not let a model invent action fields, infer numeric types, or sign arbitrary JSON.
</Note>

## Separate reasoning from signing

A secure agent stack should have distinct responsibilities:

<CardGroup cols={2}>
  <Card title="Context and planning" icon="brain">
    Reads documentation and current state, then proposes a structured action with a rationale. It has no access to private keys.
  </Card>

  <Card title="Policy engine" icon="shield-check">
    Enforces allowed actions, contract allowlists, precision, maximum size, leverage, reduce-only constraints, price bands, and account-level exposure limits.
  </Card>

  <Card title="Signer" icon="signature">
    Accepts only validated canonical actions, assigns or verifies a unique nonce, signs with the agent key, and returns the signature envelope.
  </Card>

  <Card title="Reconciler" icon="arrows-rotate">
    Confirms orders, cancellations, fills, positions, and authorization state from server responses and WebSocket events.
  </Card>
</CardGroup>

The model should never call the signer with free-form text. Define a strict proposal schema such as:

```json theme={"system"}
{
  "intent": "place_order",
  "contractId": 1,
  "side": "buy",
  "price": "50",
  "size": "1",
  "timeInForce": "Gtc",
  "reduceOnly": false,
  "reason": "Spread and inventory conditions satisfy strategy rules"
}
```

Your application then maps the validated proposal to the compact API action fields.

## Expiry and rotation policy

For production systems, avoid permanent authorization unless there is a strong operational reason. A practical policy is:

1. Use a named agent for each environment and strategy, such as `maker-prod` or `risk-staging`.
2. Set a finite `validUntil` and alert well before expiry.
3. Create and approve a replacement wallet before the current authorization expires.
4. Verify the replacement through `userAgents`.
5. Switch the signer and run a low-risk health check.
6. Revoke the previous address and confirm it is no longer used by any process.

Because `userAgents` includes expired entries, your monitoring should distinguish `validUntil = 0`, future timestamps, and expired timestamps rather than assuming every returned record is active.

## Kill switch

A kill switch should operate independently of the model and trading strategy:

* Stop the order-generation loop.
* Disable or isolate the signing service.
* Cancel open orders where operationally appropriate.
* Revoke the agent with `revokeAgent`, signed by the master account.
* Confirm authorization state through `userAgents`.
* Reconcile late responses and in-flight requests before declaring the incident closed.

<Warning>
  Revocation takes effect when it is recorded by the exchange. A request already in flight may still be accepted if it arrives before the revocation is processed, so continue reconciliation after triggering the kill switch.
</Warning>

## Common failure modes

| Symptom                           | Likely cause                                                                | Response                                                                                          |
| --------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `SIGNATURE_INVALID`               | Wrong private key, incorrect canonical JSON, double hashing, or invalid `v` | Rebuild the signed message exactly as documented and compare the recovered address                |
| Duplicate or rejected nonce       | The signing address reused a nonce or concurrent workers raced              | Maintain one monotonic nonce allocator per agent address                                          |
| Agent not authorized              | Authorization expired, was revoked, or targets a different master account   | Query `userAgents`, verify the target account, and re-approve only after operator review          |
| Named quota full                  | Three distinct named slots are already occupied                             | Revoke or intentionally replace an existing named agent                                           |
| Address belongs to another master | The wallet is already registered under a different master account           | Generate a fresh dedicated wallet rather than sharing one agent address                           |
| State drift after submission      | REST or WebSocket reconciliation is delayed or disconnected                 | Pause new writes, refresh account and order state, then resume only after consistency checks pass |

## Related API pages

<CardGroup cols={2}>
  <Card title="approveAgent" icon="user-plus" href="/exchange/approve-agent">
    Authorize an agent address, name it, and optionally set an expiry.
  </Card>

  <Card title="revokeAgent" icon="user-minus" href="/exchange/revoke-agent">
    Remove an agent authorization and free its quota slot.
  </Card>

  <Card title="userAgents" icon="users" href="/info/user-agents">
    Audit active and expired agent records for a master account.
  </Card>

  <Card title="Authentication" icon="signature" href="/guide/authentication">
    Sign `POST /exchange` requests with EIP-712 over secp256k1 — Agent and typed paths.
  </Card>

  <Card title="Nonce" icon="clock" href="/guide/nonce">
    Generate unique replay-protection values for each signing address.
  </Card>

  <Card title="Write requests" icon="upload" href="/guide/write-requests">
    Review the shared `POST /exchange` envelope and proxy fields.
  </Card>
</CardGroup>
