As an extra layer of security, the Fig Markets API supports HMAC-SHA256 signatures to verify that requests are coming from authorized clients and haven't been tampered with during transmission.
This guide explains how to authenticate your API requests using HMAC-SHA256 signatures.
Currently, all GET, POST, PUT and DELETE requests require signature authentication.
- Request Preparation: Your client creates a request with method, URI, and body
- String Construction: A specific string format is created from your request
- Signature Generation: HMAC-SHA256 is used to sign the string with your client secret
- Header Addition: The signature and timestamp are added as HTTP headers
- Request Transmission: The signed request is sent to the API
Every authenticated request must include these headers:
| Header | Description | Example |
|---|---|---|
X-FIG-Signature | HMAC-SHA256 signature of the request | a1b2c3d4e5f6... |
X-FIG-Timestamp | Unix timestamp when request was created | 1703123456 |
Authorization | JWT bearer token | Bearer eyJhbGciOiJSUzI1NiIs... |
The signature is calculated from a string with this exact format:
<timestamp>\n<http-method>\n<request-uri>\n<request-body>The timestamp used to generate the signature must be the same as the X-FIG-Timestamp header.
DELETE Request (Delete RFQ):
1703123456
DELETE
/rfq/12345POST Request (Create RFQ):
1703123456
POST
/rfq
{"baseCurrency":"BTC","quoteCurrency":"USD","amount":1.5,"anonymous":false,"settlementCredentials":"DBT-main","legs":[{"direction":"buy","instrumentId":12345,"ratio":1}]}GET Request (Get RFQ by ID):
1703123456
GET
/rfq/12345Important Notes:
- Use uppercase HTTP methods (GET, POST, PUT, DELETE)
- Include the full URI path with query parameters
- For
GETrequests, the body is empty (just two newlines) - For
DELETErequests with path parameters, the body is empty (just two newlines) - For
DELETErequests with request body, include the exact JSON body - For
POST/PUTrequests, include the exact JSON body - Maintain exact newline characters (
\n)
const crypto = require('crypto');
class FigAPIClient {
constructor(baseUrl, clientSecret, jwtToken) {
this.baseUrl = baseUrl;
this.clientSecret = clientSecret;
this.jwtToken = jwtToken;
}
// Generate signature for a request
generateSignature(timestamp, method, uri, body = '') {
const stringToSign = `${timestamp}\n${method}\n${uri}\n${body}`;
const hmac = crypto.createHmac('sha256', this.clientSecret);
hmac.update(stringToSign);
return hmac.digest('hex');
}
// Make an authenticated request
async makeRequest(method, endpoint, body = null) {
const uri = endpoint;
const bodyString = body ? JSON.stringify(body) : '';
const signature = this.generateSignature(timestamp, method, uri, bodyString);
const timestamp = Math.floor(Date.now() / 1000).toString();
const headers = {
'X-FIG-Signature': signature,
'X-FIG-Timestamp': timestamp,
'Authorization': `Bearer ${this.jwtToken}`,
'Content-Type': 'application/json'
};
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: method,
headers: headers,
body: bodyString || undefined
});
return response;
}
// Example methods
async createRFQ(rfqData) {
return this.makeRequest('POST', '/rfq', rfqData);
}
async deleteRFQ(rfqId) {
return this.makeRequest('DELETE', `/rfq/${rfqId}`);
}
async deleteQuote(quoteData) {
return this.makeRequest('DELETE', '/rfq/quote', quoteData);
}
}
// Usage example
const client = new FigAPIClient(
'https://api.figmarkets.com/v1',
'your-client-secret',
'your-jwt-token'
);
// Create RFQ request
const rfqData = {
baseCurrency: 'BTC',
quoteCurrency: 'USD',
amount: 1.5,
anonymous: false,
settlementCredentials: 'DBT-main',
legs: [
{
direction: 'buy',
instrumentId: 12345,
ratio: 1
}
]
};
const rfq = await client.createRFQ(rfqData);
// Delete RFQ request
const deleteResponse = await client.deleteRFQ(12345);
// Delete Quote request
const quoteData = {
rfqId: 12345,
rfqQuoteId: 67890,
label: 'MyQuote-123'
};
const quoteDeleteResponse = await client.deleteQuote(quoteData);import hmac
import hashlib
import time
import requests
import json
class FigAPIClient:
def __init__(self, base_url, client_secret, jwt_token):
self.base_url = base_url
self.client_secret = client_secret.encode('utf-8')
self.jwt_token = jwt_token
def generate_signature(self, timestamp, method, uri, body=''):
"""Generate HMAC-SHA256 signature for the request"""
string_to_sign = f"{timestamp}\n{method}\n{uri}\n{body}"
signature = hmac.new(
self.client_secret,
string_to_sign.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
def make_request(self, method, endpoint, body=None):
"""Make an authenticated request to the API"""
uri = endpoint
body_string = json.dumps(body) if body else ''
signature = self.generate_signature(timestamp, method, uri, body_string)
timestamp = str(int(time.time()))
headers = {
'X-FIG-Signature': signature,
'X-FIG-Timestamp': timestamp,
'Authorization': f'Bearer {self.jwt_token}',
'Content-Type': 'application/json'
}
url = f"{self.base_url}{endpoint}"
if method.upper() == 'GET':
response = requests.get(url, headers=headers)
elif method.upper() == 'DELETE':
if body:
response = requests.delete(url, headers=headers, json=body)
else:
response = requests.delete(url, headers=headers)
else:
response = requests.post(url, headers=headers, json=body)
return response
def create_rfq(self, rfq_data):
"""Create a new RFQ"""
return self.make_request('POST', '/rfq', rfq_data)
def delete_rfq(self, rfq_id):
"""Delete an RFQ by ID"""
return self.make_request('DELETE', f'/rfq/{rfq_id}')
def delete_quote(self, quote_data):
"""Delete a quote"""
return self.make_request('DELETE', '/rfq/quote', quote_data)
# Usage example
client = FigAPIClient(
'https://api.figmarkets.com/v1',
'your-client-secret',
'your-jwt-token'
)
# Create RFQ request
rfq_data = {
'baseCurrency': 'BTC',
'quoteCurrency': 'USD',
'amount': 1.5,
'anonymous': False,
'settlementCredentials': 'DBT-main',
'legs': [
{
'direction': 'buy',
'instrumentId': 12345,
'ratio': 1
}
]
}
response = client.create_rfq(rfq_data)
print(response.json())
# Delete RFQ request
delete_response = client.delete_rfq(12345)
print(delete_response.json())
# Delete Quote request
quote_data = {
'rfqId': 12345,
'rfqQuoteId': 67890,
'label': 'MyQuote-123'
}
quote_delete_response = client.delete_quote(quote_data)
print(quote_delete_response.json())package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
)
type FigAPIClient struct {
BaseURL string
ClientSecret string
JWTToken string
HTTPClient *http.Client
}
func NewFigAPIClient(baseURL, clientSecret, jwtToken string) *FigAPIClient {
return &FigAPIClient{
BaseURL: baseURL,
ClientSecret: clientSecret,
JWTToken: jwtToken,
HTTPClient: &http.Client{},
}
}
func (c *FigAPIClient) generateSignature(method, uri, body string) string {
stringToSign := fmt.Sprintf("%s\n%s\n%s", method, uri, body)
mac := hmac.New(sha256.New, []byte(c.ClientSecret))
mac.Write([]byte(stringToSign))
return hex.EncodeToString(mac.Sum(nil))
}
func (c *FigAPIClient) makeRequest(method, endpoint string, body interface{}) (*http.Response, error) {
uri := endpoint
bodyString := ""
if body != nil {
bodyBytes, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyString = string(bodyBytes)
}
signature := c.generateSignature(method, uri, bodyString)
timestamp := fmt.Sprintf("%d", time.Now().Unix())
url := c.BaseURL + endpoint
var req *http.Request
var err error
if method == "GET" {
req, err = http.NewRequest(method, url, nil)
} else if method == "DELETE" && body != nil {
req, err = http.NewRequest(method, url, strings.NewReader(bodyString))
} else if method == "DELETE" {
req, err = http.NewRequest(method, url, nil)
} else {
req, err = http.NewRequest(method, url, strings.NewReader(bodyString))
}
if err != nil {
return nil, err
}
req.Header.Set("X-FIG-Signature", signature)
req.Header.Set("X-FIG-Timestamp", timestamp)
req.Header.Set("Authorization", "Bearer "+c.JWTToken)
req.Header.Set("Content-Type", "application/json")
return c.HTTPClient.Do(req)
}
func (c *FigAPIClient) CreateRFQ(rfqData map[string]interface{}) (*http.Response, error) {
return c.makeRequest("POST", "/rfq", rfqData)
}
func (c *FigAPIClient) DeleteRFQ(rfqId int) (*http.Response, error) {
return c.makeRequest("DELETE", fmt.Sprintf("/rfq/%d", rfqId), nil)
}
func (c *FigAPIClient) DeleteQuote(quoteData map[string]interface{}) (*http.Response, error) {
return c.makeRequest("DELETE", "/rfq/quote", quoteData)
}
// Usage example
func main() {
client := NewFigAPIClient(
"https://api.figmarkets.com/v1",
"your-client-secret",
"your-jwt-token",
)
// Create RFQ request
rfqData := map[string]interface{}{
"baseCurrency": "BTC",
"quoteCurrency": "USD",
"amount": 1.5,
"anonymous": false,
"settlementCredentials": "DBT-main",
"legs": []map[string]interface{}{
{
"direction": "buy",
"instrumentId": 12345,
"ratio": 1,
},
},
}
resp, err := client.CreateRFQ(rfqData)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer resp.Body.Close()
fmt.Printf("Create RFQ Status: %s\n", resp.Status)
// Delete RFQ request
resp, err = client.DeleteRFQ(12345)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer resp.Body.Close()
fmt.Printf("Delete RFQ Status: %s\n", resp.Status)
// Delete Quote request
quoteData := map[string]interface{}{
"rfqId": 12345,
"rfqQuoteId": 67890,
"label": "MyQuote-123",
}
resp, err = client.DeleteQuote(quoteData)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer resp.Body.Close()
fmt.Printf("Delete Quote Status: %s\n", resp.Status)
}