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

# HMAC Authentication

This page describes API request authentication. It is not wallet signing. Every private endpoint request must include an HMAC value in `x-api-sign`.

## Authentication payload

Five lines joined by `\n`:

```
METHOD
URI
TIMESTAMP
NONCE
RAW_BODY
```

| Field       | Description                                               |
| ----------- | --------------------------------------------------------- |
| `METHOD`    | Uppercase HTTP method.                                    |
| `URI`       | Path with sorted query string. No domain or context path. |
| `TIMESTAMP` | Same as `x-api-ts` (ms).                                  |
| `NONCE`     | Same as `x-api-nonce`.                                    |
| `RAW_BODY`  | Raw body string, or empty if none.                        |

## Query string sorting

Parameters sorted by name ascending. Example request:

```
GET /api/v1/orders?page=1&limit=10
```

Authenticated `URI`:

```
/api/v1/orders?limit=10&page=1
```

> Avoid duplicate query parameter names when building the authentication payload.

## Body authentication

JSON requests use `Content-Type: application/json`. `RAW_BODY` must match the sent body exactly (spaces, field order).

`GET` and bodyless `POST` use empty `RAW_BODY`.

## HMAC-SHA256

```
x-api-sign = hex(HMAC_SHA256(authenticationPayload, apiSecret))
```

UTF-8 encoding throughout.

### Python

```python
import hmac
import hashlib
from urllib.parse import urlencode

def canonical_uri(path: str, query: dict = None) -> str:
    if not query:
        return path
    sorted_pairs = sorted(query.items(), key=lambda x: x[0])
    return f"{path}?{urlencode(sorted_pairs)}"

def sign_trading_api(
    method: str,
    path: str,
    query: dict = None,
    timestamp: int = None,
    nonce: str = None,
    raw_body: str = "",
    api_secret: str = "",
) -> str:
    import time
    import uuid
    timestamp = timestamp or int(time.time() * 1000)
    nonce = nonce or str(uuid.uuid4())
    uri = canonical_uri(path, query)
    payload = f"{method.upper()}\n{uri}\n{timestamp}\n{nonce}\n{raw_body}"
    return hmac.new(
        api_secret.encode("utf-8"),
        payload.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()
```

### cURL

cURL + openssl works for a quick check, but shell HMAC has sharp edges (trailing-newline stripping by `$(...)`, secrets starting with `-`, `date +%s%3N` on macOS/BSD, `PATH` clobbering). For production, prefer the Python example above or the Node `crypto` version in [examples.md](/trading-api/authentication/examples.md).

```bash
METHOD="GET"
URI="/api/v1/symbols"
# Unix milliseconds. GNU date works directly; BSD (macOS) date emits a literal "N",
# so fall back based on whether the output is all digits (do NOT rely on exit code —
# BSD date exits 0 even for %3N).
TIMESTAMP=$(date +%s%3N)
case "$TIMESTAMP" in
  ''|*[!0-9]*)
    if command -v gdate >/dev/null 2>&1; then TIMESTAMP=$(gdate +%s%3N)
    else TIMESTAMP=$(python3 -c 'import time; print(int(time.time()*1000))'); fi ;;
esac
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')
RAW_BODY=""
# Pipe printf STRAIGHT into openssl. Three gotchas this avoids:
#  1) Join with REAL newlines (printf format), not the two-character "\n".
#  2) PAYLOAD=$(printf ...) would strip the trailing newline -> wrong sig for empty-body (GET/DELETE) requests.
#  3) -macopt "key:..." (not -hmac "...") so a secret starting with "-" isn't parsed as an openssl option.
HMAC_AUTH=$(printf '%s\n%s\n%s\n%s\n%s' "$METHOD" "$URI" "$TIMESTAMP" "$NONCE" "$RAW_BODY" \
  | openssl dgst -sha256 -mac HMAC -macopt "key:$API_SECRET" -hex | awk '{print $NF}')

curl -X GET "https://rwa-api.anchored.finance/rwa/trading/api/v1/symbols" \
  -H "x-api-key: ${API_KEY}" \
  -H "x-api-ts: ${TIMESTAMP}" \
  -H "x-api-nonce: ${NONCE}" \
  -H "x-api-sign: ${HMAC_AUTH}" \
  -H "x-api-chain-id: 8453" \
  -H "x-api-p: Anchored"
```
