> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/api-reference/guides/authentication.md).

# Authentication

EVM wallet sign-in and API key management. Four operations.

Two credentials are involved, and they are not interchangeable:

1. **Session token** — obtained by signing a fixed message with your EVM wallet (EIP-191 `personal_sign`). It is a `Bearer` token, it lasts **24 hours**, and it authenticates the `/keys` endpoints **only**. You cannot trade with it.
2. **API key** — a `key_id` + `secret` pair minted with the session token. Every trading and account request is HMAC-SHA256 signed with the secret. The secret is returned **once** at creation and is never stored or shown again.

```
POST /auth/login   (wallet signature)         → session Bearer token
POST /keys         (Bearer)                    → key_id + secret
sign each request  (HMAC over canonical str)   → trade
```

For delegated signing that avoids exposing your main wallet, see [Agents](/api-reference/guides/agent-keys.md).

Base URL for every example below: `https://exchange.nexus.xyz/api/exchange`.

***

## `POST /auth/login`

Sign in with EVM wallet.

Submit an EIP-191 `personal_sign` signature to receive a session token. The session token is used to create and manage API keys via `/keys` endpoints. For trading, use HMAC API keys instead. Session tokens expire after 24 hours.

**Authentication:** None — the request authenticates itself with the wallet signature it carries.

### Request body

`LoginRequest` — `application/json`, required.

| Field       | Type   | Required | Description                                         |
| ----------- | ------ | -------- | --------------------------------------------------- |
| `message`   | string | Yes      | Must be exactly: `Sign in to Nexus Exchange`        |
| `signature` | string | Yes      | EIP-191 `personal_sign` hex (0x-prefixed, 65 bytes) |

The message is a fixed string, not a nonce challenge — there is no separate "request a challenge" call. Your wallet address is *recovered* from the signature, so it is not sent.

### Responses

#### `200`

Session created. `LoginResponse`.

| Field     | Type   | Description                                                               |
| --------- | ------ | ------------------------------------------------------------------------- |
| `token`   | string | Session token (64-char hex). Use as `Bearer` token for `/keys` endpoints. |
| `address` | string | Recovered Ethereum address (0x-prefixed)                                  |

#### `401`

Signature verification failed.

### Example

```bash
curl -X POST 'https://exchange.nexus.xyz/api/exchange/auth/login' \
  -H 'Content-Type: application/json' \
  -d '{
    "message": "Sign in to Nexus Exchange",
    "signature": "0x1234...abcd"
  }'
```

Response:

```json
{
  "token": "a1b2c3d4e5f6...",
  "address": "0xAbCdEf0123456789..."
}
```

***

## `POST /keys`

Create an API key.

Create a new HMAC API key for the authenticated wallet. Returns the secret once — it is never stored or shown again. Requires a session token (Bearer) from `POST /auth/login`.

**Authentication:** `bearerAuth` — session token.

### Request body

None declared in the contract. Send the request with no body.

> **Gap:** the guided quickstart on the live API-docs page sends an optional `{"label": "my-bot"}` body to this endpoint, but spec 0.9.27 declares no `requestBody` for `createApiKey`. Treat `label` as undocumented until the contract carries it.

### Responses

#### `200`

Key created.

| Field    | Type   | Description                                                                                  |
| -------- | ------ | -------------------------------------------------------------------------------------------- |
| `key_id` | string | The key identifier. Send it as `X-API-Key` on signed requests.                               |
| `secret` | string | The HMAC secret, hex. **Returned once.** Persist it immediately — there is no recovery path. |

The contract gives this response an example but no named schema.

#### `401`

Valid session token required.

### Example

```bash
curl -X POST 'https://exchange.nexus.xyz/api/exchange/keys' \
  -H 'Authorization: Bearer a1b2c3d4e5f6...'
```

Response:

```json
{
  "key_id": "nx_a1b2c3d4e5f67890",
  "secret": "deadbeef..."
}
```

New keys are assigned the **Pro** tier by default. Tier assignment is an operator action — see [`PUT /admin/tiers`](/api-reference/admin/set-tier.md) — and per-tier ceilings are reported on every response in the `X-RateLimit-*` headers.

***

## `GET /keys`

List your API keys.

Returns key IDs and tiers for all keys owned by the authenticated wallet. Secrets are not included.

**Authentication:** `bearerAuth` — session token.

### Responses

#### `200`

The session's API keys. A bare array; the contract gives an example but no named schema.

| Field    | Type   | Description                                                      |
| -------- | ------ | ---------------------------------------------------------------- |
| `key_id` | string | The key identifier                                               |
| `tier`   | string | Rate-limit tier assigned to this key, e.g. `Pro`, `Market Maker` |

#### `401`

Valid session token required.

### Example

```bash
curl 'https://exchange.nexus.xyz/api/exchange/keys' \
  -H 'Authorization: Bearer a1b2c3d4e5f6...'
```

Response:

```json
[
  {
    "key_id": "nx_a1b2c3d4e5f67890",
    "tier": "Pro"
  }
]
```

***

## `DELETE /keys/{key_id}`

Delete an API key.

Delete a key you own. Cannot delete keys owned by other wallets.

**Authentication:** `bearerAuth` — session token.

### Parameters

| Name     | In   | Type   | Required | Description                  |
| -------- | ---- | ------ | -------- | ---------------------------- |
| `key_id` | path | string | Yes      | The key identifier to delete |

### Responses

#### `200`

Key deleted.

#### `401`

Valid session token required.

#### `404`

Key not found or not owned by you. Ownership failures are reported as `404`, not `403` — you cannot probe for other wallets' key IDs.

### Example

```bash
curl -X DELETE 'https://exchange.nexus.xyz/api/exchange/keys/nx_a1b2c3d4e5f67890' \
  -H 'Authorization: Bearer a1b2c3d4e5f6...'
```

***

## Signing a request with the key

Once you hold a `key_id` and `secret`, every `hmacAuth` operation needs three headers:

| Header        | Value                                   |
| ------------- | --------------------------------------- |
| `X-API-Key`   | Your key ID, e.g. `nx_a1b2c3d4e5f67890` |
| `X-Timestamp` | Current time in Unix **milliseconds**   |
| `X-Signature` | `hex(hmac_sha256(secret, canonical))`   |

The canonical string is five newline-separated fields:

```
<timestamp>\n<METHOD>\n<path>\n<query>\n<sha256_hex(body)>
```

* `path` is the path **as written in the contract** — *not* the full URL path you called. The `/api/exchange` gateway mount is stripped before the request reaches the service that verifies your signature, so it must **not** be signed. Do include the `/api/v1` prefix when calling a versioned path, because that part is forwarded.

  | You call                                                 | You sign          |
  | -------------------------------------------------------- | ----------------- |
  | `https://exchange.nexus.xyz/api/exchange/markets`        | `/markets`        |
  | `https://exchange.nexus.xyz/api/exchange/api/v1/tickers` | `/api/v1/tickers` |

  Signing the `/api/exchange` prefix is the second most common cause of an opaque `401`, after clock skew.
* `query` is the raw query string, empty for none.
* For requests with no body, hash the empty string.
* The timestamp must be within **30 seconds** of server time. A skewed clock is the most common cause of an opaque `401`.

The advisory `X-Nexus-Api-Version` and `User-Agent` headers are **excluded** from the canonical string.

```bash
TIMESTAMP=$(python3 -c 'import time; print(int(time.time()*1000))')
BODY_HASH=$(printf '' | shasum -a 256 | cut -d' ' -f1)
CANONICAL="$TIMESTAMP\nGET\n/markets\n\n$BODY_HASH"
SIGNATURE=$(printf '%s' "$CANONICAL" | openssl dgst -sha256 -mac HMAC \
  -macopt "hexkey:$NEXUS_API_SECRET" -hex | awk '{print $NF}')

curl 'https://exchange.nexus.xyz/api/exchange/markets' \
  -H "X-API-Key: nx_a1b2c3d4e5f67890" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "X-Signature: $SIGNATURE"
```

All `401` responses return the same opaque body — `{"code":"unauthorized"}` — so the response will not tell you whether the key, the signature, or the clock was at fault. Check clock skew first, then the canonical string, then the key.

> **Status:** testnet preview. Credentials, sessions, and rate-limit state are not yet durable across gateway restarts — treat API keys as re-creatable.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexus.xyz/api-reference/guides/authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
