Generate Request Signature
Orderly uses the ed25519 elliptic curve standard for request authentication via signature verification.
Orderly Account ID
Register your account and obtain your account ID. The registration steps are provided here .
Add your account ID to the request header as orderly-account-id.
Orderly Key
Add your Orderly public key to the request header as orderly-key. To generate and add a new Orderly Key, see the documentation .
You can also obtain Orderly keys from frontend builders like WOOFi Pro .
Timestamp
Take the current timestamp in milliseconds and add it as orderly-timestamp to the request header.
Normalize request content
Normalize the message to a string by concatenating the following:
Current timestamp in milliseconds, e.g. 1649920583000
HTTP method in uppercase, e.g. POST
Request path including query parameters (without base URL), e.g. /v1/orders?symbol=PERP_BTC_USDC
(Optional) If the request has a body, JSON stringify it and append
Example result: 1649920583000POST/v1/order{"symbol": "PERP_ETH_USDC", "order_type": "LIMIT", "order_price": 1521.03, "order_quantity": 2.11, "side": "BUY"}
Generate signature
Sign the normalized content using the ed25519 algorithm, encode the signature in base64 url-safe format, and add the result to the request header as orderly-signature.
Content type
Set the Content-Type header:
GET and DELETE: application/x-www-form-urlencoded
POST and PUT: application/json
Send the request
The final request should have the following headers: Header Description Content-TypeRequest content type orderly-account-idYour Orderly account ID orderly-keyYour Orderly public key orderly-signatureed25519 signature (base64url) orderly-timestampRequest timestamp (ms)
The Orderly Key should be used without the ed25519: prefix when used in code samples below.
Minimal Example
This is a concise, single-file TypeScript example that demonstrates how to sign and send a request to the Orderly API using the @noble/ed25519 library.
import { signAsync , getPublicKeyAsync } from '@noble/ed25519' ;
import bs58 from 'bs58' ;
async function main () {
const orderlyAccountId = 'YOUR_ACCOUNT_ID' ;
const orderlySecret = 'YOUR_ORDERLY_SECRET' ; // base58 encoded
const baseUrl = 'https://testnet-api.orderly.org' ;
const url = new URL ( ` ${ baseUrl } /v1/order` );
const method = 'POST' ;
const body = JSON . stringify ({
symbol: 'PERP_ETH_USDC' ,
order_type: 'MARKET' ,
order_quantity: 0.01 ,
side: 'BUY'
});
const timestamp = Date . now ();
const privateKey = bs58 . decode ( orderlySecret );
const message = ` ${ timestamp }${ method }${ url . pathname }${ url . search }${ body } ` ;
const signature = await signAsync ( new TextEncoder (). encode ( message ), privateKey );
const response = await fetch ( url , {
method ,
body ,
headers: {
'Content-Type' : 'application/json' ,
'orderly-account-id' : orderlyAccountId ,
'orderly-key' : `ed25519: ${ bs58 . encode ( await getPublicKeyAsync ( privateKey )) } ` ,
'orderly-timestamp' : String ( timestamp ),
'orderly-signature' : Buffer . from ( signature ). toString ( 'base64url' ),
},
});
const data = await response . json ();
console . log ( data );
}
main ();
Full Example
Java
Python
TypeScript
Shell
AuthenticationExample.java
Signer.java
import io.github.cdimascio.dotenv.Dotenv;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.bitcoinj.base.Base58;
import org.json.JSONObject;
public class AuthenticationExample {
public static void main ( String [] args ) throws Exception {
String baseUrl = "https://testnet-api.orderly.org" ;
String orderlyAccountId = "<orderly-account-id>" ;
Dotenv dotenv = Dotenv . load ();
OkHttpClient client = new OkHttpClient ();
String key = dotenv . get ( "ORDERLY_SECRET" );
EdDSAParameterSpec spec = EdDSANamedCurveTable . getByName ( EdDSANamedCurveTable . ED_25519 );
EdDSAPrivateKeySpec encoded = new EdDSAPrivateKeySpec ( Base58 . decode (key), spec);
EdDSAPrivateKey orderlyKey = new EdDSAPrivateKey (encoded);
Signer signer = new Signer (baseUrl, orderlyAccountId, orderlyKey);
JSONObject json = new JSONObject ();
json . put ( "symbol" , "PERP_ETH_USDC" );
json . put ( "order_type" , "MARKET" );
json . put ( "order_quantity" , 0.01 );
json . put ( "side" , "BUY" );
Request req = signer . createSignedRequest ( "/v1/order" , "POST" , json);
String res ;
try ( Response response = client . newCall (req). execute ()) {
res = response . body (). string ();
}
JSONObject obj = new JSONObject (res);
}
}
authentication_example.py
signer.py
import json
import os
from base58 import b58decode
from requests import Request, Session
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from signer import Signer
base_url = "https://testnet-api.orderly.org"
orderly_account_id = "<orderly-account-id>"
key = b58decode(os.environ.get( "ORDERLY_SECRET" ))
orderly_key = Ed25519PrivateKey.from_private_bytes(key)
session = Session()
signer = Signer(orderly_account_id, orderly_key)
req = signer.sign_request(
Request(
"POST" ,
" %s /v1/order" % base_url,
json = {
"symbol" : "PERP_ETH_USDC" ,
"order_type" : "MARKET" ,
"order_quantity" : 0.01 ,
"side" : "BUY" ,
},
)
)
res = session.send(req)
response = json.loads(res.text)
authenticationExample.ts
signer.ts
import bs58 from 'bs58' ;
import { config } from 'dotenv' ;
import { webcrypto } from 'node:crypto' ;
import { signAndSendRequest } from "./signer" ;
// this is only necessary in Node.js to make `@noble/ed25519` dependency work
if ( ! globalThis . crypto ) globalThis . crypto = webcrypto as any ;
config ();
async function main () {
const baseUrl = 'https://testnet-api.orderly.org' ;
const orderlyAccountId = '<orderly-account-id>' ;
const orderlyKey = bs58 . decode ( process . env . ORDERLY_SECRET ! );
const res = await signAndSendRequest ( orderlyAccountId , orderlyKey , ` ${ baseUrl } /v1/order` , {
method: 'POST' ,
body: JSON . stringify ({
symbol: 'PERP_ETH_USDC' ,
order_type: 'MARKET' ,
order_quantity: 0.01 ,
side: 'BUY'
})
});
const response = await res . json ();
console . log ( response );
}
main ();
curl --request POST \
--url https://api.orderly.org/v1/order \
--header 'Content-Type: application/json' \
--header 'orderly-account-id: <orderly-account-id>' \
--header 'orderly-key: ed25519:8tm7dnKYkSc3FzgPuJaw1wztr79eeZpN35nHW5pL5XhX' \
--header 'orderly-signature: dG4bkKiqG0dUYLzViRZkvbI6Sy239JxAdNMIBxFZ4w030Jofr0ORV06GHtvXZkaZaWUXE+XAU3fnzKN/5fDeBQ==' \
--header 'orderly-timestamp: 1649920583000' \
--data '{
"symbol": "<symbol>",
"order_type": "<order_type>",
"side": "<side>",
"reduce_only": false
}'
Security
Orderly validates every request through three checks. A request must pass all three to be accepted.
Request Timestamp
The request is rejected if the orderly-timestamp header differs from the API server time by more than 300 seconds.
Signature Verification
The orderly-signature header must be a valid ed25519 signature generated from the normalized request content and signed with your Orderly secret key.
Orderly Key Validity
The orderly-key header must reference a key that has been added to the network, is associated with the account, and has not expired.