REST API کامل
دسترسی به دادههای بازار، موجودی حساب و سفارشگذاری از طریق endpointهای ساده و مستند.
API اکسیر
با مجموعه کامل توابع REST و WebSocket اکسیر، باتهای معاملهگر و استراتژیهای الگوریتمی خود را روی یکی از معتبرترین بازارهای ارز دیجیتال ایران اجرا کنید. مستندات کامل همین صفحه است — از احراز هویت تا آخرین endpoint.
# GET /v2/ticker?symbol=btc-usdt
{
"symbol": "btc-usdt",
"last": "64850.2",
"high": "65120.0",
"low": "63870.5",
"open": "64010.7",
"volume": "182.43"
} دسترسی به دادههای بازار، موجودی حساب و سفارشگذاری از طریق endpointهای ساده و مستند.
تغییر قیمت، دفتر سفارش و معاملات را بدون وقفه و با کمترین تأخیر دریافت کنید.
زیرساخت مناسب برای اجرای استراتژیهای خودکار، باتهای معاملهگر و Algo Trading.
برای هر کلید مجوزهای جداگانه تعریف کنید و دسترسی برنامهها را بهصورت امن مدیریت نمایید.
کتابخانه exir-node-lib روی npm منتشر شده تا بدون درگیرشدن با جزئیات امضا و WebSocket به اکسیر متصل شوید.
ticker، دفتر سفارش، معاملات و داده نمودار همه بازارهای اکسیر در دسترس شماست.
دادههای عمومی بازار بدون نیاز به احراز هویت در دسترساند. کافی است یک درخواست بزنید.
# قیمت لحظهای بیتکوین به تتر
curl "https://api.exir.io/v2/ticker?symbol=btc-usdt"const res = await fetch(
"https://api.exir.io/v2/ticker?symbol=btc-usdt"
);
const ticker = await res.json();
console.log(ticker.last);import requests
res = requests.get(
"https://api.exir.io/v2/ticker",
params={"symbol": "btc-usdt"},
)
print(res.json()["last"])// قیمت لحظهای بیتکوین به تتر
$res = file_get_contents("https://api.exir.io/v2/ticker?symbol=btc-usdt");
$ticker = json_decode($res, true);
echo $ticker["last"];using System.Text.Json;
using var http = new HttpClient();
var json = await http.GetStringAsync(
"https://api.exir.io/v2/ticker?symbol=btc-usdt");
var ticker = JsonDocument.Parse(json).RootElement;
Console.WriteLine(ticker.GetProperty("last"));
کتابخانه exir-node-lib امضای HMAC، مدیریت
کلیدها و اتصال WebSocket (با اتصال مجدد خودکار) را برای شما انجام میدهد تا مستقیم سراغ
منطق معاملاتیتان بروید.
$ npm install exir-node-lib const Exir = require("exir-node-lib");
const client = new Exir({
apiKey: "<API_KEY>",
apiSecret: "<API_SECRET>",
});
// REST — امضای درخواستها خودکار انجام میشود
const balance = await client.getBalance();
const order = await client.createOrder(
"btc-usdt", "buy", 0.001, "market"
);
// WebSocket — اتصال و اشتراک با یک خط
client.connect(["orderbook:btc-usdt", "order", "wallet"]);
client.ws.on("message", (data) => {
console.log(JSON.parse(data));
}); برای endpointهای خصوصی ابتدا از بخش امنیت حساب کاربری کلید API بسازید. هر درخواست خصوصی باید سه هدر زیر را داشته باشد:
| هدر | توضیح |
|---|---|
api-key | کلید API شما |
api-signature | امضای HMAC-SHA256 درخواست با کلید مخفی (خروجی hex) |
api-expires | زمان انقضای درخواست بهصورت Unix timestamp (ثانیه) — مثلاً ۶۰ ثانیه بعد |
امضا روی رشتهای از متد HTTP، مسیر کامل (همراه query string)، زمان انقضا و — در صورت وجود — بدنه JSON درخواست محاسبه میشود:
# قالب رشته امضا
METHOD + PATH + api-expires + JSON_BODY
# نمونهها
GET/v2/user/balance1575516146
POST/v2/order1583284849{"symbol":"btc-usdt","side":"buy","size":0.001,"type":"market"} const crypto = require("crypto");
const method = "GET";
const path = "/v2/user/balance";
const expires = Math.floor(Date.now() / 1000) + 60;
const signature = crypto
.createHmac("sha256", API_SECRET)
.update(method + path + expires)
.digest("hex");
const res = await fetch("https://api.exir.io" + path, {
headers: {
"api-key": API_KEY,
"api-signature": signature,
"api-expires": String(expires),
},
});
console.log(await res.json());
پایه آدرس: https://api.exir.io/v2
— endpointهای علامتخورده با
کلید API
نیازمند احراز هویت هستند.
این endpointها بدون احراز هویت در دسترساند.
/health وضعیت و سلامت سرویس /constants لیست بازارها و ارزهای فعال بههمراه مشخصات هر یک /kit تنظیمات و اطلاعات عمومی صرافی /tiers سطحهای کاربری و ساختار کارمزد هر سطح /ticker قیمت لحظهای یک بازار در ۲۴ ساعت گذشته | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار، مثلاً btc-usdt |
/tickers قیمت لحظهای همه بازارها /orderbook دفتر سفارش (خرید و فروش) یک بازار | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار، مثلاً btc-usdt |
/orderbooks دفتر سفارش همه بازارها /trades آخرین معاملات انجامشده | پارامتر | نوع | توضیح |
|---|---|---|
symbol | string | نماد بازار؛ بدون آن معاملات همه بازارها برمیگردد |
/chart داده کندل (OHLCV) یک بازار برای نمودار | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار، مثلاً btc-usdt |
resolution الزامی | string | تایمفریم: 15، 60، 240 (دقیقه)، 1D یا 1W |
from الزامی | timestamp | ابتدای بازه (Unix timestamp) |
to الزامی | timestamp | انتهای بازه (Unix timestamp) |
/charts داده کندل همه بازارها | پارامتر | نوع | توضیح |
|---|---|---|
resolution الزامی | string | تایمفریم: 15، 60، 240 (دقیقه)، 1D یا 1W |
from الزامی | timestamp | ابتدای بازه (Unix timestamp) |
to الزامی | timestamp | انتهای بازه (Unix timestamp) |
/minicharts داده فشرده نمودار برای نمایش چند ارز کنار هم | پارامتر | نوع | توضیح |
|---|---|---|
assets الزامی | string | لیست ارزها، جداشده با ویرگول |
quote | string | ارز مبنا برای قیمتگذاری |
/quick-trade استعلام نرخ تبدیل سریع دو ارز | پارامتر | نوع | توضیح |
|---|---|---|
spending_currency الزامی | string | ارزی که پرداخت میکنید |
receiving_currency الزامی | string | ارزی که دریافت میکنید |
spending_amount | number | مقدار پرداختی (یکی از دو مقدار کافی است) |
receiving_amount | number | مقدار دریافتی (یکی از دو مقدار کافی است) |
نیازمند احراز هویت با کلید API.
/user
کلید API
اطلاعات حساب کاربری شما /user/balance
کلید API
موجودی کیف پول برای همه ارزها /user/trades
کلید API
تاریخچه معاملات شما | پارامتر | نوع | توضیح |
|---|---|---|
symbol | string | فیلتر بر اساس نماد بازار |
limit | number | تعداد آیتمها در هر صفحه (پیشفرض ۵۰، حداکثر ۱۰۰) |
page | number | شماره صفحه |
order_by | string | فیلدی که داده بر اساس آن مرتب میشود |
order | asc | desc | ترتیب صعودی یا نزولی |
start_date | ISO8601 | ابتدای بازه زمانی |
end_date | ISO8601 | انتهای بازه زمانی |
format | string | با مقدار csv خروجی بهصورت فایل CSV برمیگردد |
نیازمند احراز هویت با کلید API.
/user/deposits
کلید API
لیست واریزهای شما | پارامتر | نوع | توضیح |
|---|---|---|
currency | string | فیلتر بر اساس ارز (مثلاً btc) |
status | boolean | فقط تراکنشهای تکمیلشده |
dismissed | boolean | فقط تراکنشهای لغوشده |
rejected | boolean | فقط تراکنشهای ردشده |
processing | boolean | فقط تراکنشهای در حال پردازش |
waiting | boolean | فقط تراکنشهای در انتظار |
transaction_id | string | فیلتر بر اساس شناسه تراکنش (TXID) |
address | string | فیلتر بر اساس آدرس کیف پول |
limit | number | تعداد آیتمها در هر صفحه (پیشفرض ۵۰، حداکثر ۱۰۰) |
page | number | شماره صفحه |
order_by | string | فیلدی که داده بر اساس آن مرتب میشود |
order | asc | desc | ترتیب صعودی یا نزولی |
start_date | ISO8601 | ابتدای بازه زمانی |
end_date | ISO8601 | انتهای بازه زمانی |
format | string | با مقدار csv خروجی بهصورت فایل CSV برمیگردد |
/user/withdrawals
کلید API
لیست برداشتهای شما | پارامتر | نوع | توضیح |
|---|---|---|
currency | string | فیلتر بر اساس ارز (مثلاً btc) |
status | boolean | فقط تراکنشهای تکمیلشده |
dismissed | boolean | فقط تراکنشهای لغوشده |
rejected | boolean | فقط تراکنشهای ردشده |
processing | boolean | فقط تراکنشهای در حال پردازش |
waiting | boolean | فقط تراکنشهای در انتظار |
transaction_id | string | فیلتر بر اساس شناسه تراکنش (TXID) |
address | string | فیلتر بر اساس آدرس کیف پول |
limit | number | تعداد آیتمها در هر صفحه (پیشفرض ۵۰، حداکثر ۱۰۰) |
page | number | شماره صفحه |
order_by | string | فیلدی که داده بر اساس آن مرتب میشود |
order | asc | desc | ترتیب صعودی یا نزولی |
start_date | ISO8601 | ابتدای بازه زمانی |
end_date | ISO8601 | انتهای بازه زمانی |
format | string | با مقدار csv خروجی بهصورت فایل CSV برمیگردد |
/user/withdrawal/fee
کلید API
کارمزد برداشت یک ارز | پارامتر | نوع | توضیح |
|---|---|---|
currency الزامی | string | نماد ارز، مثلاً btc |
/user/withdrawal
کلید API
ثبت درخواست برداشت | پارامتر | نوع | توضیح |
|---|---|---|
currency الزامی | string | نماد ارز، مثلاً btc |
amount الزامی | number | مقدار برداشت |
address الزامی | string | آدرس کیف پول مقصد |
network | string | شبکه انتقال، در صورتی که ارز چند شبکه داشته باشد |
نیازمند احراز هویت با کلید API.
/orders
کلید API
لیست سفارشهای شما | پارامتر | نوع | توضیح |
|---|---|---|
symbol | string | فیلتر بر اساس نماد بازار |
side | buy | sell | فیلتر بر اساس سمت سفارش |
open | boolean | فقط سفارشهای باز |
limit | number | تعداد آیتمها در هر صفحه (پیشفرض ۵۰، حداکثر ۱۰۰) |
page | number | شماره صفحه |
order_by | string | فیلدی که داده بر اساس آن مرتب میشود |
order | asc | desc | ترتیب صعودی یا نزولی |
start_date | ISO8601 | ابتدای بازه زمانی |
end_date | ISO8601 | انتهای بازه زمانی |
format | string | با مقدار csv خروجی بهصورت فایل CSV برمیگردد |
/order
کلید API
جزئیات یک سفارش | پارامتر | نوع | توضیح |
|---|---|---|
order_id الزامی | string | شناسه سفارش |
/order
کلید API
ثبت سفارش جدید | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار، مثلاً btc-usdt |
side الزامی | buy | sell | سمت سفارش |
size الزامی | number | مقدار سفارش |
type الزامی | limit | market | نوع سفارش |
price | number | قیمت — برای سفارش limit الزامی است |
stop | number | قیمت فعالسازی سفارش استاپ |
meta.post_only | boolean | سفارش فقط بهصورت میکر ثبت شود |
meta.note | string | یادداشت دلخواه روی سفارش |
# درخواست
POST /v2/order
{"symbol":"btc-usdt","side":"buy","size":0.001,"type":"market"}
# پاسخ
{
"id": "7d3d9545-b7e6-4e7f-84a0-a39efa4cb173",
"symbol": "btc-usdt",
"side": "buy",
"size": 0.001,
"type": "market",
"filled": 0,
"status": "new",
"fee": 0,
"fee_coin": "usdt",
"fee_structure": { "maker": 0.2, "taker": 0.2 },
"created_at": "2021-02-17T03:03:19.231Z"
} /order
کلید API
لغو یک سفارش | پارامتر | نوع | توضیح |
|---|---|---|
order_id الزامی | string | شناسه سفارش |
/order/all
کلید API
لغو همه سفارشهای باز یک بازار | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار، مثلاً btc-usdt |
/order/execute
کلید API
اجرای معامله تبدیل سریع با کد استعلام | پارامتر | نوع | توضیح |
|---|---|---|
token الزامی | string | توکن دریافتی از استعلام /quick-trade |
برای اتصال مستقیم کتابخانه نمودار TradingView (پروتکل UDF). بدون نیاز به احراز هویت.
/udf/config تنظیمات UDF برای TradingView /udf/history تاریخچه کندل با قرارداد UDF | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار |
resolution الزامی | string | تایمفریم: 15، 60، 240 (دقیقه)، 1D یا 1W |
from الزامی | timestamp | ابتدای بازه (Unix timestamp) |
to الزامی | timestamp | انتهای بازه (Unix timestamp) |
/udf/symbols مشخصات نماد با قرارداد UDF | پارامتر | نوع | توضیح |
|---|---|---|
symbol الزامی | string | نماد بازار |
آدرس اتصال: wss://api.exir.io/stream
— برای دریافت بلادرنگ دفتر سفارش، معاملات و رویدادهای حساب. اگر تا ۶۰ ثانیه پیامی رد و بدل
نشود اتصال قطع میشود؛ هر ۳۰ ثانیه یک پیام ping بفرستید.
# اشتراک در کانالها
{ "op": "subscribe", "args": ["orderbook:btc-usdt", "trade"] }
# لغو اشتراک
{ "op": "unsubscribe", "args": ["trade"] }
# پیام keep-alive (هر ۳۰ ثانیه)
{ "op": "ping" }
همان امضای HMAC-SHA256 بخش REST، اینبار بهصورت پارامترهای query string و با رشته امضای
CONNECT/stream + api-expires:
# اتصال خصوصی: پارامترهای احراز هویت در query string
wss://api.exir.io/stream?api-key=...&api-signature=...&api-expires=...
# رشته امضا برای WebSocket
CONNECT/stream1583284849 const ws = new WebSocket("wss://api.exir.io/stream");
ws.onopen = () => {
ws.send(JSON.stringify({
op: "subscribe",
args: ["orderbook:btc-usdt", "trade:btc-usdt"],
}));
};
ws.onmessage = (event) => console.log(JSON.parse(event.data)); {
"topic": "orderbook",
"action": "partial",
"symbol": "btc-usdt",
"data": {
"bids": [[64850.2, 0.12]],
"asks": [[64851.0, 0.08]],
"timestamp": "2020-12-15T06:45:27.766Z"
},
"time": 1608015328
} orderbook دفتر سفارش — با orderbook:btc-usdt فقط یک بازار، بدون نماد همه بازارها trade معاملات لحظهای — با trade:btc-usdt فقط یک بازار، بدون نماد همه بازارها تنها با اتصال احراز هویتشده در دسترساند.
order ایجاد و بهروزرسانی سفارشهای شما usertrade اجرای معاملات شما wallet تغییرات موجودی کیف پول deposit اعلان واریز جدید withdrawal اعلان برداشت جدید partial تصویر اولیه داده هنگام اشتراک (حداکثر ۵۰ آیتم، به ترتیب نزولی) insert افزودهشدن آیتم جدید update بهروزرسانی آیتم موجود خطاها با کد وضعیت استاندارد HTTP برمیگردند. توجه کنید که تعداد درخواستها محدودیت نرخ (Rate Limit) دارد و در صورت عبور از آن، پاسخ ۴۲۹ دریافت میکنید.
| کد | عنوان | توضیح |
|---|---|---|
400 | Bad Request | درخواست نامعتبر است — پارامترها را بررسی کنید |
401 | Unauthorized | احراز هویت ناموفق — کلید API یا امضا نامعتبر است |
403 | Forbidden | دسترسی به این منبع مجاز نیست |
404 | Not Found | منبع موردنظر پیدا نشد |
405 | Method Not Allowed | متد HTTP برای این آدرس پشتیبانی نمیشود |
406 | Not Acceptable | درخواست قابل پذیرش نیست |
410 | Gone | این منبع دیگر در دسترس نیست |
429 | Too Many Requests | عبور از محدودیت تعداد درخواست — کمی صبر کنید و دوباره تلاش کنید |
500 | Internal Server Error | خطای داخلی سرور |
503 | Service Unavailable | سرویس موقتاً در دسترس نیست |
یک سناریوی کامل و آماده اجرا: دریافت موجودی کیف پول، ثبت یک سفارش limit، دریافت همان
سفارش با شناسه و سپس اتصال به کانال wallet
از طریق WebSocket برای دریافت لحظهای تغییرات موجودی. کافی است کلید و رمز API خود را
جایگزین کنید. نسخه Node.js از کتابخانه رسمی exir-node-lib استفاده میکند؛ بقیه زبانها
بدون وابستگی خاص، مستقیم با REST و WebSocket کار میکنند.
// npm install exir-node-lib
const Exir = require('exir-node-lib');
const client = new Exir({
apiKey: '<API_KEY>',
apiSecret: '<API_SECRET>',
});
const main = async () => {
// موجودی کیف پول
const balance = await client.getBalance();
console.log('balance:', balance);
// ثبت سفارش limit
const order = await client.createOrder('btc-usdt', 'buy', 0.001, 'limit', 50000);
console.log('created order:', order);
// دریافت همان سفارش با شناسه
const fetched = await client.getOrder(order.id);
console.log('order:', fetched);
// WebSocket: اشتراک در همه کانالهای خصوصی (ping را خود کتابخانه میفرستد)
// wallet: موجودی، order: وضعیت سفارشها، usertrade: اجرای معاملات،
// deposit / withdrawal: وضعیت واریز و برداشت
client.connect(['wallet', 'order', 'usertrade', 'deposit', 'withdrawal']);
client.ws.on('message', (raw) => {
const message = JSON.parse(raw);
if (!message.topic) return; // پیامهای سیستمی مثل pong
console.log(message.topic, message.action, message.data);
});
};
main().catch(console.error);# pip install requests websocket-client
import hashlib
import hmac
import json
import threading
import time
import requests
import websocket
API_KEY = '<API_KEY>'
API_SECRET = '<API_SECRET>'
BASE_URL = 'https://api.exir.io'
def sign(payload):
return hmac.new(API_SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest()
def auth_headers(method, path, body=''):
expires = str(int(time.time()) + 60)
return {
'api-key': API_KEY,
'api-signature': sign(method + path + expires + body),
'api-expires': expires,
'Content-Type': 'application/json',
}
# موجودی کیف پول
balance = requests.get(
BASE_URL + '/v2/user/balance',
headers=auth_headers('GET', '/v2/user/balance'),
).json()
print('balance:', balance)
# ثبت سفارش limit
body = json.dumps(
{'symbol': 'btc-usdt', 'side': 'buy', 'size': 0.001, 'type': 'limit', 'price': 50000},
separators=(',', ':'),
)
order = requests.post(
BASE_URL + '/v2/order',
headers=auth_headers('POST', '/v2/order', body),
data=body,
).json()
print('created order:', order)
# دریافت همان سفارش با شناسه
path = '/v2/order?order_id=' + order['id']
print('order:', requests.get(BASE_URL + path, headers=auth_headers('GET', path)).json())
# WebSocket: اشتراک در کانال wallet
expires = str(int(time.time()) + 60)
ws_url = (
'wss://api.exir.io/stream'
f'?api-key={API_KEY}&api-signature={sign("CONNECT/stream" + expires)}&api-expires={expires}'
)
def keep_alive(ws):
# هر ۳۰ ثانیه یک ping بفرستید تا اتصال باز بماند
while True:
time.sleep(30)
ws.send(json.dumps({'op': 'ping'}))
def on_open(ws):
# wallet: موجودی، order: وضعیت سفارشها، usertrade: اجرای معاملات،
# deposit / withdrawal: وضعیت واریز و برداشت
ws.send(json.dumps({
'op': 'subscribe',
'args': ['wallet', 'order', 'usertrade', 'deposit', 'withdrawal'],
}))
threading.Thread(target=keep_alive, args=(ws,), daemon=True).start()
def on_message(ws, raw):
message = json.loads(raw)
if 'topic' in message:
print(message['topic'], message.get('action'), message.get('data'))
ws = websocket.WebSocketApp(ws_url, on_open=on_open, on_message=on_message)
ws.run_forever()<?php
// composer require textalk/websocket
require __DIR__ . '/vendor/autoload.php';
use WebSocket\Client;
$apiKey = '<API_KEY>';
$apiSecret = '<API_SECRET>';
$baseUrl = 'https://api.exir.io';
function apiRequest($method, $path, $body = null)
{
global $apiKey, $apiSecret, $baseUrl;
$expires = time() + 60;
$bodyJson = $body === null ? '' : json_encode($body);
$signature = hash_hmac('sha256', $method . $path . $expires . $bodyJson, $apiSecret);
$ch = curl_init($baseUrl . $path);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'api-key: ' . $apiKey,
'api-signature: ' . $signature,
'api-expires: ' . $expires,
'Content-Type: application/json',
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson);
}
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// موجودی کیف پول
$balance = apiRequest('GET', '/v2/user/balance');
echo 'balance: ' . json_encode($balance) . PHP_EOL;
// ثبت سفارش limit
$order = apiRequest('POST', '/v2/order', [
'symbol' => 'btc-usdt',
'side' => 'buy',
'size' => 0.001,
'type' => 'limit',
'price' => 50000,
]);
echo 'created order: ' . json_encode($order) . PHP_EOL;
// دریافت همان سفارش با شناسه
$fetched = apiRequest('GET', '/v2/order?order_id=' . $order['id']);
echo 'order: ' . json_encode($fetched) . PHP_EOL;
// WebSocket: اشتراک در کانال wallet
$expires = time() + 60;
$signature = hash_hmac('sha256', 'CONNECT/stream' . $expires, $apiSecret);
$ws = new Client(
"wss://api.exir.io/stream?api-key=$apiKey&api-signature=$signature&api-expires=$expires",
['timeout' => 30]
);
// wallet: موجودی، order: وضعیت سفارشها، usertrade: اجرای معاملات،
// deposit / withdrawal: وضعیت واریز و برداشت
$ws->send(json_encode([
'op' => 'subscribe',
'args' => ['wallet', 'order', 'usertrade', 'deposit', 'withdrawal'],
]));
while (true) {
try {
$message = json_decode($ws->receive(), true);
if (isset($message['topic'])) {
echo $message['topic'] . ' ' . $message['action'] . ' ' . json_encode($message['data']) . PHP_EOL;
}
} catch (\WebSocket\TimeoutException $e) {
// هر ۳۰ ثانیه سکوت، یک ping بفرستید تا اتصال باز بماند
$ws->send(json_encode(['op' => 'ping']));
}
}// .NET 6+ — بدون وابستگی خارجی (dotnet run)
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
const string ApiKey = "<API_KEY>";
const string ApiSecret = "<API_SECRET>";
const string BaseUrl = "https://api.exir.io";
string Sign(string payload)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(ApiSecret));
return Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))).ToLowerInvariant();
}
var http = new HttpClient();
async Task<JsonElement> ApiRequestAsync(HttpMethod method, string path, string? body = null)
{
var expires = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60;
var request = new HttpRequestMessage(method, BaseUrl + path);
request.Headers.Add("api-key", ApiKey);
request.Headers.Add("api-signature", Sign($"{method}{path}{expires}{body}"));
request.Headers.Add("api-expires", expires.ToString());
if (body != null)
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await http.SendAsync(request);
return JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
}
// موجودی کیف پول
var balance = await ApiRequestAsync(HttpMethod.Get, "/v2/user/balance");
Console.WriteLine($"balance: {balance}");
// ثبت سفارش limit
var orderBody = JsonSerializer.Serialize(new
{
symbol = "btc-usdt",
side = "buy",
size = 0.001,
type = "limit",
price = 50000,
});
var order = await ApiRequestAsync(HttpMethod.Post, "/v2/order", orderBody);
Console.WriteLine($"created order: {order}");
// دریافت همان سفارش با شناسه
var orderId = order.GetProperty("id").GetString();
var fetched = await ApiRequestAsync(HttpMethod.Get, $"/v2/order?order_id={orderId}");
Console.WriteLine($"order: {fetched}");
// WebSocket: اشتراک در کانال wallet
var wsExpires = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60;
var wsUrl = "wss://api.exir.io/stream" +
$"?api-key={ApiKey}&api-signature={Sign($"CONNECT/stream{wsExpires}")}&api-expires={wsExpires}";
using var ws = new ClientWebSocket();
await ws.ConnectAsync(new Uri(wsUrl), CancellationToken.None);
async Task SendAsync(object message) => await ws.SendAsync(
Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message)),
WebSocketMessageType.Text, true, CancellationToken.None);
// wallet: موجودی، order: وضعیت سفارشها، usertrade: اجرای معاملات،
// deposit / withdrawal: وضعیت واریز و برداشت
await SendAsync(new { op = "subscribe", args = new[] { "wallet", "order", "usertrade", "deposit", "withdrawal" } });
// هر ۳۰ ثانیه یک ping بفرستید تا اتصال باز بماند
_ = Task.Run(async () =>
{
while (ws.State == WebSocketState.Open)
{
await Task.Delay(TimeSpan.FromSeconds(30));
await SendAsync(new { op = "ping" });
}
});
var buffer = new byte[65536];
while (ws.State == WebSocketState.Open)
{
var result = await ws.ReceiveAsync(buffer, CancellationToken.None);
var message = JsonDocument.Parse(Encoding.UTF8.GetString(buffer, 0, result.Count)).RootElement;
if (message.TryGetProperty("topic", out var topic))
Console.WriteLine(topic + " " + message.GetProperty("action") + " " + message.GetProperty("data"));
}
هر پیام دریافتی سه فیلد اصلی دارد: topic
(نام کانال)، action و
data. مقدار action یکی از
partial (تصویر اولیه که بلافاصله پس از
اشتراک میرسد)، insert (آیتم جدید) یا
update (بهروزرسانی آیتم موجود) است:
wallet بلافاصله پس از اشتراک یک partial با موجودی همه ارزها میرسد؛ سپس با هر تغییر موجودی (اجرای معامله، واریز یا برداشت) یک update با موجودی جدید دریافت میکنید. order partial اولیه حداکثر ۵۰ سفارش اخیر شما را برمیگرداند؛ ثبت سفارش جدید insert و هر تغییر وضعیت (new ← pfilled ← filled یا canceled) یک update میفرستد. usertrade هر بار سفارش شما — کامل یا بخشی از آن — اجرا شود، یک insert با جزئیات معامله (قیمت، مقدار، کارمزد) میرسد. deposit ثبت واریز جدید insert میفرستد و تغییر وضعیت آن (مثلاً پس از تأیید شبکه یا تکمیل) با update اعلام میشود. withdrawal مانند deposit برای برداشتها؛ از ثبت درخواست تا تکمیل یا رد شدن، وضعیت با insert و update دنبال میشود. کلید API خود را بسازید و با exir-node-lib یا چند خط fetch ساده، اولین درخواست را بزنید.