curl --request POST \
--url https://api.limitless.exchange/profiles/partner-accounts \
--header 'Content-Type: application/json' \
--header 'lmts-api-key: <api-key>' \
--data '
{
"displayName": "user-alice",
"createServerWallet": false
}
'import requests
url = "https://api.limitless.exchange/profiles/partner-accounts"
payload = {
"displayName": "user-alice",
"createServerWallet": False
}
headers = {
"lmts-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'lmts-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({displayName: 'user-alice', createServerWallet: false})
};
fetch('https://api.limitless.exchange/profiles/partner-accounts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.limitless.exchange/profiles/partner-accounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'displayName' => 'user-alice',
'createServerWallet' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"lmts-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.limitless.exchange/profiles/partner-accounts"
payload := strings.NewReader("{\n \"displayName\": \"user-alice\",\n \"createServerWallet\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("lmts-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.limitless.exchange/profiles/partner-accounts")
.header("lmts-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"displayName\": \"user-alice\",\n \"createServerWallet\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.limitless.exchange/profiles/partner-accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["lmts-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"displayName\": \"user-alice\",\n \"createServerWallet\": false\n}"
response = http.request(request)
puts response.read_body{
"profileId": 789,
"account": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}Create Partner Sub-Account
Creates a new sub-account linked to the authenticated partner. Requires HMAC authentication with the account_creation scope.
Server wallet mode (createServerWallet: true): Creates a Privy server wallet and profile. The partner can then submit orders on behalf of this account using delegated signing.
EOA mode (default): Requires wallet ownership verification via x-account, x-signing-message, and x-signature headers. The end user signs their own orders.
curl --request POST \
--url https://api.limitless.exchange/profiles/partner-accounts \
--header 'Content-Type: application/json' \
--header 'lmts-api-key: <api-key>' \
--data '
{
"displayName": "user-alice",
"createServerWallet": false
}
'import requests
url = "https://api.limitless.exchange/profiles/partner-accounts"
payload = {
"displayName": "user-alice",
"createServerWallet": False
}
headers = {
"lmts-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'lmts-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({displayName: 'user-alice', createServerWallet: false})
};
fetch('https://api.limitless.exchange/profiles/partner-accounts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.limitless.exchange/profiles/partner-accounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'displayName' => 'user-alice',
'createServerWallet' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"lmts-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.limitless.exchange/profiles/partner-accounts"
payload := strings.NewReader("{\n \"displayName\": \"user-alice\",\n \"createServerWallet\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("lmts-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.limitless.exchange/profiles/partner-accounts")
.header("lmts-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"displayName\": \"user-alice\",\n \"createServerWallet\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.limitless.exchange/profiles/partner-accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["lmts-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"displayName\": \"user-alice\",\n \"createServerWallet\": false\n}"
response = http.request(request)
puts response.read_body{
"profileId": 789,
"account": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}account_creation scope. API key auth and Privy auth are not accepted.profileId, use List Partner Sub-Accounts
with the account filter to recover it.
Server wallet mode
SetcreateServerWallet: true to create a Privy server wallet for the sub-account. This enables delegated signing — you can submit unsigned orders and the server signs them using the managed wallet.
Before the first delegated trade, call Check Partner Account Allowances. If any target is missing or failed with retryable=true, call Retry Partner Account Allowances, then poll the check endpoint again.
delegated_signing scope on your API token (in addition to account_creation). Without it, the request returns "Server wallet creation requires delegated_signing scope".{
"displayName": "user-bob",
"createServerWallet": true
}
EOA mode
OmitcreateServerWallet (or set it to false) to create an account for an externally-owned address. The end user manages their own keys and signs their own orders.
EOA mode requires three additional headers for wallet ownership verification:
| Header | Description |
|---|---|
x-account | Checksummed Ethereum address (EIP-55) |
x-signing-message | Hex-encoded signing message obtained from GET /auth/signing-message |
x-signature | Hex-encoded signature produced by signing the message with the wallet |
Signing message format
Thex-signing-message value is not the raw text — it is the hex-encoded UTF-8 representation of the message returned by GET /auth/signing-message. The raw text (which you sign) looks like:
Welcome to Limitless Exchange!
This request will not trigger a blockchain transaction or cost any gas fees.
Signature is required to authenticate an upcoming API request.
Nonce: 0x<keccak256-hash>
- Fetch the signing message:
GET /auth/signing-message→ returns the plain-text message with a unique nonce. - Sign the plain-text message with the wallet (e.g.
personal_sign/eth_sign). - Hex-encode the plain-text message: prepend
0xto the UTF-8 hex representation. - Send all three headers on the request.
import requests
from eth_account import Account
from eth_account.messages import encode_defunct
# 1. Fetch the signing message
signing_message = requests.get(f"{API_BASE_URL}/auth/signing-message").text
# 2. Sign the plain-text message
message = encode_defunct(text=signing_message)
signed = account.sign_message(message)
# 3. Hex-encode the message for the header
hex_message = "0x" + signing_message.encode("utf-8").hex()
# 4. Use in headers
headers = {
"x-account": account.address, # checksummed address
"x-signing-message": hex_message, # hex-encoded message
"x-signature": "0x" + signed.signature.hex(), # hex-encoded signature
}
import { createWalletClient, http, toHex } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';
// 1. Fetch the signing message
const signingMessage = await fetch(`${API_BASE_URL}/auth/signing-message`).then(r => r.text());
// 2. Sign the plain-text message
const account = privateKeyToAccount(PRIVATE_KEY);
const signature = await account.signMessage({ message: signingMessage });
// 3. Hex-encode the message for the header
const hexMessage = toHex(new TextEncoder().encode(signingMessage));
// 4. Use in headers
const headers = {
'x-account': account.address, // checksummed address
'x-signing-message': hexMessage, // hex-encoded message
'x-signature': signature, // hex-encoded signature
};
{
"displayName": "user-alice"
}
Constraints
displayNameis optional (max 44 characters). Defaults to the wallet address if omitted.- Returns
409 Conflictif a profile already exists for the target address. - Cannot create a sub-account for the partner’s own address.
Authorizations
Scoped API token with HMAC-SHA256 signing. Requires three headers: lmts-api-key (token ID), lmts-timestamp (ISO-8601), lmts-signature (Base64-encoded HMAC). See Authentication docs for details.
Headers
EOA mode only. Checksummed Ethereum address of the sub-account wallet.
EOA mode only. Hex-encoded signing message.
EOA mode only. Hex-encoded signature from the sub-account wallet.
Body
Public display name for the sub-account. Defaults to the wallet address if omitted.
44"user-alice"
If true, creates a Privy server wallet for the sub-account (enables delegated signing). If false or omitted, requires EOA wallet ownership headers.