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

# AFK API v1

> Overview and conventions for AFK Crypto API v1

## Overview

* Base path: `/api/v1`
* Authentication: API key via `x-api-key` header
* Idempotency: write operations require `Idempotency-Key` header (UUID format)
* Response format: all responses include `x-request-id` header for tracking

### Endpoints

* `GET /api/v1/wallets` – List user wallets
* `GET /api/v1/wallets/balances` – Get balances for caller's wallet (by chain; defaults to default wallet)
* `GET /api/v1/wallets/:address/balances` – Get balances for a specific owned wallet
* `GET /api/v1/tx/:id` – Get transaction details
* `POST /api/v1/send` – Send native assets and tokens (EVM + Solana)
* `POST /api/v1/token/approve` – ERC20 token approval (EVM only)
* `POST /api/v1/contracts/send` – Generic contract interaction (EVM only)
* `POST /api/v1/trade/quote` – Get swap quotes (EVM + Solana)
* `POST /api/v1/trade/swap` – Execute swaps (EVM + Solana)

## Chains

See the full list in [Supported chains](/api-reference/supported-chains/). Use the `chain` slug (for example, `base`, `solana-devnet`).

## Rate limiting

* **Writes** (including `POST /api/v1/trade/quote`): 15 requests per minute per user
* **Reads**: 60 requests per minute per user
* Response: HTTP 429 when exceeded
* Headers: `Retry-After` (seconds until next window)

## Idempotency (writes)

* All mutating endpoints require `Idempotency-Key`.
* Reusing a key with the exact same request body returns the original 200 response.
* Reusing a key with a different body returns HTTP 409 with `code: IDEMPOTENT_BODY_MISMATCH`.
* Reusing a key with no stored success response returns HTTP 409 with `code: IDEMPOTENT_REPLAY`.
* Keys are scoped to the authenticated user; the endpoint path is recorded for traceability.
* Applies to: `POST /api/v1/send`, `POST /api/v1/token/approve`, `POST /api/v1/contracts/send`, `POST /api/v1/trade/swap`.

## Error handling

### Error response format

```json theme={null}
{
  "error": "Human-readable error message",
  "code": "ERROR_CODE",
  "requestId": "unique-request-id"
}
```

### Error codes

* `UNAUTHORIZED` – Missing/invalid auth or API key (HTTP 401)
* `FORBIDDEN` – Authenticated but not allowed to perform the action (HTTP 403)
* `NOT_FOUND` – Resource not found (HTTP 404)
* `RATE_LIMITED` – Rate limit exceeded (HTTP 429)
* `INVALID_INPUT` – Invalid request parameters (HTTP 400)
* `WALLET_NOT_FOUND` – Specified wallet not found
* `USER_NOT_LINKED` – User not linked to Privy
* `WALLET_NOT_DELEGATED` – Wallet not delegated to server signer
* `WALLET_ID_REQUIRED` – Missing Privy wallet ID
* `CHAIN_UNKNOWN` – Unknown or unsupported chain
* `INSUFFICIENT_FUNDS` – Sender lacks funds for value/fee
* `IDEMPOTENT_BODY_MISMATCH` – Different request body with same idempotency key (HTTP 409)
* `IDEMPOTENT_REPLAY` – Idempotency key already used (HTTP 409)
* `PRIVY_RPC_ERROR` – Error from Privy RPC service
* `SEND_FAILED` – Transaction submission failed
* `SERVICE_UNAVAILABLE` – Required service not configured
* `QUOTE_FAILED` – Quote service error (HTTP 400)
* `INTERNAL_ERROR` – Server error

<Note>
  **QUOTE\_FAILED specifics:**

  * **Solana/Jupiter**: Some Solana mints are not tradable on Jupiter (curated allowlist). In those cases, this API returns HTTP 400 with `code: QUOTE_FAILED` and an error message like: "Token not tradable on Jupiter".
  * **EVM/1inch**: If a token is not supported by 1inch, the API returns HTTP 400 with `code: QUOTE_FAILED` and a message like: "Token not tradable on 1inch".
  * This is expected when the requested output token/mint is marked non-tradable by the upstream provider, even if pools exist elsewhere.
</Note>

## Validation

### Address formats

* EVM: must match `/^0x[a-fA-F0-9]{40}$/`
* Solana: must be a valid base58 public key

### Common parameters

* **Amounts (EVM)**: Integer strings only (decimal or 0x-hex). Must be non-negative. For ERC20 and `value`, must fit uint256.
* **Amounts (Solana)**: Integer strings in base units. SPL amounts must fit unsigned 64-bit range.
* **Sender (`from`)**: Optional. If omitted, the user's default wallet for the specified chain is used.
* **Idempotency**: All write endpoints require `Idempotency-Key` header. Repeats with the same body return the original response.

### Native token keyword

Trade endpoints (`/api/v1/trade/quote`, `/api/v1/trade/swap`) accept the case-insensitive keyword `NATIVE` for `fromToken`/`toToken`:

* **EVM**: `NATIVE` resolves to `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`
* **Solana**: `NATIVE` resolves to wrapped SOL mint `So11111111111111111111111111111111111111112`
* Responses return resolved addresses (not `NATIVE`)
* Send endpoint uses `asset: "native"` instead of token addresses for native transfers

## Conventions

* Chain selection: use the `chain` slug (for example, `base`, `base-sepolia`, `solana-devnet`).
* Solana `Transaction.chainId` sentinel mapping: `0` = mainnet, `-2` = testnet, `-3` = devnet.
* Idempotency: unique per user and key; repeats return the original response; mismatched bodies → 409.

## Related

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/api-reference/authentication/" />

  <Card title="Supported chains" icon="link-simple" href="/api-reference/supported-chains/" />

  <Card title="Policies & Security" icon="shield" href="/api-reference/policies-security/" />
</CardGroup>
