Authentication
Most Variational API calls require the request to be authenticated by an HMAC-SHA256 signature generated using an API Key and an API Secret. You can obtain those by generating API credentials for your company in the UI's settings pages.
Required Headers
All requests to Variational API endpoints requiring authentication must include 3 headers:
X-Request-Timestamp-Ms
: Unix timestamp of the request (in milliseconds)X-Variational-Key
: client API keyX-Variational-Signature
: a signature derived from the timestamp, client API key, secret, some of the request parameters and payload
For example:
curl --request GET \
--url 'https://api.testnet.variational.io/v1/addresses' \
--header 'X-Request-Timestamp-Ms: 1707254051670' \
--header 'X-Variational-Key: dfeee8ee-bb76-4194-9570-32f163a0d342' \
--header 'X-Variational-Signature: e120b1c6cbd7dcf2d465a8ba8431421d46da17cb031c02bb810104654a5d1918'
Time Accuracy
For security, we require that the timestamp you specify on the request does not differ from the current time on our API servers by more than 5 seconds.
You can access the Variational API server time using the /status
endpoint:
https://api.testnet.variational.io/v1/status
(doesn't require authentication)
Generating a Signature
A signature is generated by writing an authentication message to a byte buffer and signing it with HMAC-SHA256. The message is an ascii-encoded string consisting of the following values divided by pipe |
symbols:
{API_KEY}|{TIMESTAMP_MS}|{HTTP_METHOD}|{URL_PATH_AND_QUERY}
For example,
dfeee8ee-bb76-4194-9570-32f163a0d342|1707254051670|GET|/v1/addresses?company=30db7747-66b7-4182-a744-87c6cd899fbf
For endpoints expecting a request payload, the exact bytes of the HTTP request body must be appended to the authentication message buffer following another pipe symbol:
dfeee8ee-bb76-4194-9570-32f163a0d342|1707254051670|POST|/v1/addresses/new|{"address":"0x4264f4cbe7f50eded6a653cd4148a52cf1fd89e6"}
Python Code Examples
import time
import hmac
import hashlib
API_KEY = "dfeee8ee-bb76-4194-9570-32f163a0d342"
API_SECRET = bytes.fromhex("a432e5f89fea81fb7647c02191fb07c7c8012bae5b44bd9c30ca0320356de919")
timestamp_ms = int(time.time() * 1000) # 1707254051670
method = "GET"
url_qs = "/v1/addresses?company=30db7747-66b7-4182-a744-87c6cd899fbf"
message_bytes = f"{API_KEY}|{timestamp_ms}|{method}|{url_qs}".encode()
signature = hmac.new(API_SECRET, message_bytes, hashlib.sha256).hexdigest()
print(signature) # 1f2f1b99d87a6656d56f8b17d0c6e8609f31c7ca1899e473e0ea86804849e4d0
For requests with a JSON payload:
import time
import hmac
import hashlib
import json
API_KEY = "dfeee8ee-bb76-4194-9570-32f163a0d342"
API_SECRET = bytes.fromhex(
"a432e5f89fea81fb7647c02191fb07c7c8012bae5b44bd9c30ca0320356de919")
timestamp_ms = int(time.time() * 1000) # 1707254051670
method = "POST"
url_qs = "/v1/addresses/new"
message_bytes = bytearray(f"{API_KEY}|{timestamp_ms}|{method}|{url_qs}".encode())
payload = {"address": "0x4264f4cbe7f50eded6a653cd4148a52cf1fd89e6"}
message_bytes.extend(b"|")
message_bytes.extend(json.dumps(payload).encode())
signature = hmac.new(API_SECRET, message_bytes, hashlib.sha256).hexdigest()
print(signature) # 5213ecad43045ec0945206de00de82156605b302ed1d08e48bccb0f873137ec1
Python SDK
The provided Python SDK Client
takes care of request signing for you:
from variational import Client, TESTNET
client = Client(API_KEY, API_SECRET, base_url=TESTNET)
print(client.get_addresses().result[0]["address"])
# 0x4264f4cbe7f50eded6a653cd4148a52cf1fd89e6
If you prefer to construct the requests manually, a helper function for request signing is available:
import requests
import pprint
from variational import sign_prepared_request
url = "https://api.testnet.variational.io/v1/addresses?company=30db7747-66b7-4182-a744-87c6cd899fbf"
req = requests.Request(method="GET", url=url).prepare()
sign_prepared_request(req, API_KEY, API_SECRET)
pprint.pprint(dict(req.headers))
# ({'X-Request-Timestamp-Ms': '1707255962176',)
# ( 'X-Variational-Key': 'dfeee8ee-bb76-4194-9570-32f163a0d342',)
# ( 'X-Variational-Signature': '6f78cee1d521717d45497835232701cd02f8b7bef03ca34966100abc2258d292'})
resp = requests.Session().send(req)
print(resp.status_code) # 200
Last updated