Paradigm requires all RESToverHTTP requests to be signed.

1# A GET RESToverHTTP sample demonstrating the generation of signatures and signing of requests.
2
3import base64
4import hmac
5import time
6from urllib.parse import urljoin
7
8import requests
9
10
11def sign_request(secret_key, method, path, body):
12 signing_key = base64.b64decode(secret_key)
13
14 timestamp = str(int(time.time() * 1000)).encode('utf-8')
15 message = b'\n'.join([timestamp, method.upper(), path, body])
16 digest = hmac.digest(signing_key, message, 'sha256')
17 signature = base64.b64encode(digest)
18
19 return timestamp, signature
20
21
22access_key = '<access-key>'
23secret_key = '<secret-key>'
24host = 'https://api.testnet.paradigm.trade'
25
26# GET example
27method = b'GET'
28path = b'/v2/drfq/instruments/?venue=DBT&asset=BTC'
29body = b''
30
31timestamp, signature = sign_request(secret_key, method, path, body)
32headers = {
33 'Authorization': 'Bearer {}'.format(access_key),
34 'Paradigm-API-Timestamp': timestamp,
35 'Paradigm-API-Signature': signature,
36}
37url = urljoin(host, path.decode())
38response = requests.get(url, headers=headers)
39print(response.status_code)
40print(response.text)
1# A POST RESToverHTTP sample demonstrating the generation of signatures and signing of requests.
2
3import base64
4import hmac
5import json
6import time
7from urllib.parse import urljoin
8
9import requests
10
11
12def sign_request(secret_key, method, path, body):
13 signing_key = base64.b64decode(secret_key)
14
15 timestamp = str(int(time.time() * 1000)).encode('utf-8')
16 message = b'\n'.join([timestamp, method.upper(), path, body])
17 digest = hmac.digest(signing_key, message, 'sha256')
18 signature = base64.b64encode(digest)
19
20 return timestamp, signature
21
22
23access_key = '<access-key>'
24secret_key = '<secret-key>'
25host = 'https://api.testnet.paradigm.trade'
26
27# POST example
28method = b'POST'
29path = b'/v1/echo/'
30data = {'message': 'hello'}
31body = json.dumps(data).encode('utf-8')
32
33timestamp, signature = sign_request(secret_key, method, path, body)
34headers = {
35 'Authorization': 'Bearer {}'.format(access_key),
36 'Paradigm-API-Signature': signature,
37 'Paradigm-API-Timestamp': timestamp,
38 'Accept': 'application/json',
39}
40url = urljoin(host, path.decode())
41response = requests.post(url, headers=headers, json=data)
42print(response.status_code)
43print(response.text)

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 NameHeader Value
Paradigm-API-SignatureThe generated signature
Paradigm-API-TimestampThe timestamp used when generating the signature

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

Built with