> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.paradigm.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.paradigm.co/_mcp/server.

# Signing Requests

**Paradigm requires all RESToverHTTP requests to be signed**.

#### GET REST over HTTP example demonstrating signing of requests

```python
# A GET RESToverHTTP sample demonstrating the generation of signatures and signing of requests.

import base64
import hmac
import time
from urllib.parse import urljoin

import requests


def sign_request(secret_key, method, path, body):
    signing_key = base64.b64decode(secret_key)

    timestamp = str(int(time.time() * 1000)).encode('utf-8')
    message = b'\n'.join([timestamp, method.upper(), path, body])
    digest = hmac.digest(signing_key, message, 'sha256')
    signature = base64.b64encode(digest)

    return timestamp, signature


access_key = '<access-key>'
secret_key = '<secret-key>'
host = 'https://api.testnet.paradigm.trade'

# GET example
method = b'GET'
path = b'/v2/drfq/instruments/?venue=DBT&asset=BTC'
body = b''

timestamp, signature = sign_request(secret_key, method, path, body)
headers = {
    'Authorization': 'Bearer {}'.format(access_key),
    'Paradigm-API-Timestamp': timestamp,
    'Paradigm-API-Signature': signature,
}
url = urljoin(host, path.decode())
response = requests.get(url, headers=headers)
print(response.status_code)
print(response.text)
```

#### POST REST over HTTP example demonstrating signing of requests

```python
# A POST RESToverHTTP sample demonstrating the generation of signatures and signing of requests.

import base64
import hmac
import json
import time
from urllib.parse import urljoin

import requests


def sign_request(secret_key, method, path, body):
    signing_key = base64.b64decode(secret_key)

    timestamp = str(int(time.time() * 1000)).encode('utf-8')
    message = b'\n'.join([timestamp, method.upper(), path, body])
    digest = hmac.digest(signing_key, message, 'sha256')
    signature = base64.b64encode(digest)

    return timestamp, signature


access_key = '<access-key>'
secret_key = '<secret-key>'
host = 'https://api.testnet.paradigm.trade'

# POST example
method = b'POST'
path = b'/v1/echo/'
data = {'message': 'hello'}
body = json.dumps(data).encode('utf-8')

timestamp, signature = sign_request(secret_key, method, path, body)
headers = {
    'Authorization': 'Bearer {}'.format(access_key),
    'Paradigm-API-Signature': signature,
    'Paradigm-API-Timestamp': timestamp,
    'Accept': 'application/json',
}
url = urljoin(host, path.decode())
response = requests.post(url, headers=headers, json=data)
print(response.status_code)
print(response.text)
```

> **Warning**
>
> Signing is not currently supported for *JSON-RPCoverWebSocket* API endpoints.

Request signatures are generated by applying the HMAC-SHA256 function to your Paradigm API `<secret-key>` and a concatenated message consisting of the request timestamp, request method, request path, query parameters, and body. The key provided to the HMAC function must be the base64-decoded version of the `<secret-key>`. The signature must then be base64-encoded and passed via a special header value.

Some important considerations are:

* The timestamp must be a UNIX timestamp (milliseconds since epoch in UTC).
* The request method must be capitalized (e.g. `GET`).
* The request path must include the entire base path of the request (e.g. `/rfq/`).
* The request parameters must include `?` (e.g. `?cursor=a2Ed&venue=DBT`) unless none are used.
* The request body should be substituted with an empty string for `GET` requests.

Once the signature is generated, the timestamp and signature should be provided as HTTP headers:

| Header Name            | Header Value                                     |
| ---------------------- | ------------------------------------------------ |
| Paradigm-API-Signature | The generated signature                          |
| Paradigm-API-Timestamp | The timestamp used when generating the signature |

> **Warning**
>
> Signed requests are only valid for 30 seconds from when the timestamp is captured. Requests received after the 30-second window are rejected.