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

# API keys and WebSocket

> The vault:migrate and positions:write scopes, how to get a key that carries them, what a key can do without your signature, and the per-vault WebSocket changes.

## Scopes

| Scope | Grants | Partner key | Self-service key permission |
| - | - | - | - |
| `markets:read`, `portfolio:read`, `orders:read` | Reads | ✓ | `read` |
| `orders:write` | Place and cancel orders | ✓ | `trade` |
| `vault:migrate` (new) | `POST /api/me/vault`, `POST /api/me/vault/upgrade`, the USDC move (`POST /api/me/vault/upgrade/transfer`, `…/{id}/signature`); reads `GET /api/me/vault` and the move status | ✓ (`single_wallet` keys only) | `vault` (new) |
| `positions:write` (new) | Split / merge / convert signatures and `op-submit`, redeem, auto-redeem, on any of your vaults; reads `GET /api/me/vault` | ✓ (`single_wallet` keys only) | `vault` (new) |
| `withdraw:write` | `POST /api/withdrawals/request`, `POST /api/me/withdrawals/{id}/cancel` | ✓ (new for partner keys) | `withdraw` |
| `vault:write` | Every vault route above, the deposit relay, and the withdrawal-security (2FA / whitelist) settings | ✓ (existing keys keep working) | — |

Keys issued before this release keep exactly their scopes. A key
without `vault:migrate` or `vault:write` gets `403 api_key_scope_missing`
on the upgrade.

## Getting a key with the new scopes

| Key | How |
| - | - |
| `single_wallet` partner key | Ask your integration manager for `vault:migrate`, `positions:write` and, if the bot withdraws, `withdraw:write` |
| `multi_wallet` partner key | Multi-wallet partner keys: migration is enabled for your partner account by your integration manager once your payout addresses are listed for generation-2 withdrawals. Multi-wallet keys use `vault:write` (`vault:migrate` and `positions:write` are single-wallet only). |
| Self-service key | The web app's API-keys page will offer the Vault permission. Mint a new key with it (which grants `['vault:migrate', 'positions:write']`); existing keys keep their permissions |

## What a key can do without your signature

| Action | Needs |
| - | - |
| Create the vault, upgrade it | The key alone. The upgrade is one-way: it makes the generation-2 vault active, so deposits go there. It moves no funds |
| Move USDC between your vaults | Your `WithdrawERC20` signature on the generation-1 vault. No 2FA code |
| Orders, split / merge / convert, redeem | Your signature as before: the order, the owner signature at `op-submit`, the `RedeemAuthorization` |
| Split / merge signature requests, split / merge unlock, auto-redeem preference | The key alone; none moves value out of a vault |
| Withdraw | Your `WithdrawERC20` signature, the whitelist if set, `totpCode` if 2FA is on |
| Change 2FA or the whitelist | A partner `vault:write` key only, as before |

A leaked key with `vault:migrate` can migrate your account
irreversibly but cannot take funds. Give a bot only the scopes it uses.
Keys of a closed, blocked or banned account are refused on REST and on
the WebSocket.

## WebSocket

`/ws/user` authenticates as before. The `connected` greeting adds
`vaultAddresses`, every vault of the bound wallet:

```json theme={null}
{
  "type": "connected",
  "data": {
    "gateway":         "user",
    "walletAddress":   "0x…",
    "vaultAddress":    "0x…active at connect",
    "vaultAddresses":  ["0x…gen1", "0x…gen2"],
    "authMethod":      "api_key",
    "protocolVersion": 2
  }
}
```

`vault_positions` and `vault_activity` accept any address in
`vaultAddresses` as an id:

```json theme={null}
{ "id": "s1", "cmd": "subscribe", "params": { "subscriptions": [
  { "channel": "vault_activity",  "ids": ["0x…gen1", "0x…gen2"] },
  { "channel": "vault_positions", "ids": ["0x…gen1", "0x…gen2"] },
  { "channel": "user_activity" } ] } }
```

| Channel | Change |
| - | - |
| `user_activity` | New `vault_activated` (`{ walletAddress, vaultAddress, previousVaultAddress, generation, activatedAt }`) when the upgrade activates, and `vault_move_updated` on every USDC-move status |
| `vault_activity` | Frames name the vault in `data.vault`. Move legs carry `vaultMoveId` and `vaultMoveLeg` (`withdraw` on generation 1, `deposit` on generation 2, `refund`) |
| `vault_positions` | Frames name the vault in `data.vaultAddress` |

* Upgrading while connected: subscribe to the new vault on the same
  socket, no reconnect needed. `vaultAddress` stays the one from the
  handshake; use `vault_activated` to learn the active vault.
* Close codes: a closed, blocked or banned account is refused with
  `4401` and reason `account_closed`, `account_blocked` or
  `wallet_banned` (`account_unavailable` for a multi-wallet key's
  `X-User-Wallet`). Rotating a key closes its sockets with
  `4409 api_key_changed`; an expired key's sockets close when it
  expires.


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