شروع رایگان
راهنما / برنامه‌نویس‌ها

API باز فروشیکس (نسخه 1)

سایت اختصاصی یا فروشگاه‌ساز شما با پیاده کردن چند مسیر JSON به فروشیکس وصل می‌شود و فروشنده همه امکانات پنل (قیمت و موجودی گروهی، سفارش و ارسال، گزارش، پیامک، دستیار هوشمند و…) را برای فروشگاهش دارد؛ بدون اینکه ما برای سایت شما کدی بنویسیم.

به‌طور خلاصه: ۹ مسیر لازم (هسته) را پیاده کنید، هر درخواست را با کلید اتصال بسنجید (HMAC-SHA256)، در ping امکان‌های اختیاری‌تان را اعلام کنید، با ابزار سنجش امتحان کنید و نشانی و کلید را به فروشنده بدهید تا در «فروشگاه‌ها ← سایت دیگر (API)» وارد کند. افزونه وردپرس فروشیکس یک پیاده‌سازی کامل همین استاندارد است و نمونه خوبی برای خواندن است.

فهرست

  1. نشانی پایه و کلید
  2. امضای درخواست
  3. قالب پاسخ و خطا
  4. قواعد داده
  5. هسته (لازم)
  6. امکان‌های اختیاری
  7. سنجش و اتصال

۱. نشانی پایه و کلید اتصال

۲. امضای درخواست

هر درخواست این سرآیندها را دارد:

سرآیندمقدار
X-FY-Timestampزمان یونیکس به ثانیه
X-FY-Nonce۳۲ نویسه هگز تصادفی
X-FY-SignatureHMAC-SHA256 هگز (حروف کوچک) پیام زیر با کلید اتصال
X-FY-Actor(اختیاری) نام کاربر پنل، URL-encode شده؛ برای ثبت در تاریخچه سایت شما

پیام امضا شش خط است که با \n به هم وصل می‌شوند:

signature = hex( HMAC_SHA256( key,
    METHOD + "\n" + ROUTE + "\n" + QUERY + "\n" + TIMESTAMP + "\n" + hex(SHA256(BODY)) + "\n" + NONCE ) )

GET products?page=2  →  "GET\n/forushix/v1/remote/products\npage=2\n1767000000\ne3b0c442…b855\n9f86d081884c7d659a2feaa0c55ad015"
بخشمقدار
METHODGET یا POST با حروف بزرگ
ROUTEهمیشه /forushix/v1/remote/ و نام عملیات (مستقل از نشانی واقعی سایت شما)
QUERYپارامترهای کوئری، مرتب‌شده بر اساس نام، با کدگذاری RFC 3986 (مثل id=12&page=2)؛ بی‌پارامتر: رشته خالی
TIMESTAMPهمان X-FY-Timestamp
SHA256(BODY)هش هگز بدنه خام درخواست؛ برای GET هش رشته خالی
NONCEهمان X-FY-Nonce

سایت شما باید درخواست را رد کند (کد ۴۰۱) اگر: امضا نبود یا درست نبود، اختلاف زمان بیش از 300 ثانیه بود، یا همین امضا قبلاً یک بار پذیرفته شده بود (امضاهای دیده‌شده را دست‌کم ۱۰ دقیقه نگه دارید). مقایسه امضا را با تابع زمان‌ثابت انجام دهید.

نمونه سنجش در PHP

function fy_verify(string $secret, string $method, string $action, array $query, string $body, array $h): bool {
    $ts = $h['x-fy-timestamp'] ?? ''; $nonce = strtolower($h['x-fy-nonce'] ?? ''); $sig = strtolower($h['x-fy-signature'] ?? '');
    if (!ctype_digit($ts) || abs(time() - (int) $ts) > 300 || !preg_match('/^[a-f0-9]{32}$/', $nonce)) return false;
    ksort($query);
    $msg = strtoupper($method) . "\n" . '/forushix/v1/remote/' . $action . "\n" . http_build_query($query, '', '&', PHP_QUERY_RFC3986)
         . "\n" . $ts . "\n" . hash('sha256', $body) . "\n" . $nonce;
    if (!hash_equals(hash_hmac('sha256', $msg, $secret), $sig)) return false;
    return remember_once($sig, 600); // false اگر این امضا قبلاً دیده شده باشد
}

نمونه سنجش در Node.js

const crypto = require('crypto');
function fyVerify(secret, method, action, query, rawBody, h) {
  const ts = h['x-fy-timestamp'] || '', nonce = (h['x-fy-nonce'] || '').toLowerCase(), sig = (h['x-fy-signature'] || '').toLowerCase();
  if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300 || !/^[a-f0-9]{32}$/.test(nonce)) return false;
  const q = Object.keys(query).sort().map(k => encodeURIComponent(k) + '=' + encodeURIComponent(query[k])).join('&');
  const msg = [method.toUpperCase(), '/forushix/v1/remote/' + action, q, ts, crypto.createHash('sha256').update(rawBody || '').digest('hex'), nonce].join('\n');
  const want = crypto.createHmac('sha256', secret).update(msg).digest('hex');
  return sig.length === want.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(want)) && rememberOnce(sig, 600);
}

۳. قالب پاسخ و خطا

۴. قواعد داده

۵. هسته (لازم)

عملیاتکار
GET pingمشخصات فروشگاه و فهرست امکان‌ها
GET productsهمه محصولات
GET categoriesدسته‌ها
GET variationsتنوع‌های یک محصول (?id=)
POST pricesذخیره قیمت‌ها
POST stockذخیره موجودی
GET ordersفهرست سفارش‌ها
GET orderجزئیات یک سفارش (?id=)
POST order-statusتغییر وضعیت سفارش

GET ping

{"ok": true, "site": "فروشگاه نمونه", "url": "https://mysite.ir", "currency": "تومان", "lowStock": 5,
 "version": "1.0.0", "api": "1",
 "features": ["stats", "tracking", "notes", "customers", "reports", "events"]}

features فهرست امکان‌های اختیاری‌ای است که پیاده کرده‌اید (بخش ۶). پنل فقط همان‌ها را به فروشنده نشان می‌دهد.

GET products

{"ok": true, "data": [
  {"id": 12, "name": "شال نخی", "sku": "SH-1", "type": "simple", "status": "publish", "link": "https://mysite.ir/p/12",
   "image": "https://mysite.ir/img/12-thumb.jpg", "brand": "", "brandId": 0, "cats": ["شال"], "catIds": [3],
   "stock": "instock", "qty": 4, "manage": true, "lowAt": null,
   "regular": "250000", "sale": "199000", "price": "199000", "onSale": true},
  {"id": 13, "name": "مانتو", "type": "variable", "status": "publish", "stock": "instock", "qty": null, "manage": false,
   "regular": "", "sale": "", "price": "900000", "onSale": false, "cats": [], "catIds": []}
]}

status: publish، draft یا private. برای محصول چندحالتی قیمت و موجودی در تنوع‌هاست.

GET categories

{"ok": true, "data": [{"id": 3, "name": "شال", "parent": 0}, {"id": 4, "name": "شال تابستانی", "parent": 3}]}

GET variations?id=13

{"ok": true, "data": [
  {"id": 1301, "name": "مشکی / M", "sku": "", "stock": "instock", "qty": 3, "manage": true, "manageParent": false,
   "regular": "900000", "sale": "", "price": "900000", "onSale": false}
]}

POST prices و POST stock

بدنه فهرست تغییرهاست (حداکثر ۱۰۰۰)؛ هر فیلدی که نیامده دست نمی‌خورد. parentId برای تنوع شناسه محصول مادر است (برای محصول ساده ۰).

POST prices  {"changes": [{"id": 12, "parentId": 0, "regular": "260000", "sale": ""},
                          {"id": 1301, "parentId": 13, "sale": "850000"}]}
POST stock   {"changes": [{"id": 12, "manage": true, "qty": 7},
                          {"id": 14, "manage": false, "stock": "outofstock"}]}

پاسخ هر دو: {"ok": true, "updated": [12], "failed": [{"id": 1301, "message": "قیمت حراج باید کمتر از قیمت اصلی باشد."}]}

ردیف نامعتبر یا ناموجود به failed می‌رود و بقیه ذخیره می‌شوند. قیمت حراج باید کمتر از قیمت اصلی باشد و قیمت منفی پذیرفته نیست.

GET orders

پارامترها (همه اختیاری): status، search (نام، موبایل یا شماره سفارش)، page، per_page (۵ تا ۵۰)، from و to (Y-m-d)، customer. مرتب از تازه به قدیم.

{"ok": true, "page": 1, "totalPages": 8, "total": 152, "data": [
  {"id": 1002, "number": "1002", "status": "processing", "total": 450000, "date": "2026-10-04T14:30:00+03:30",
   "name": "سارا محمدی", "tracking": null, "source": "", "customer": 0,
   "phone": "09121112233", "address": "تهران، تهران، ونک", "postcode": "1234567890", "payment": "درگاه بانکی", "note": "",
   "items": [{"name": "شال نخی", "link": "https://mysite.ir/p/12", "qty": 2, "total": 400000}]}
]}

tracking در صورت ثبت: {"carrier": "post", "carrierName": "پست", "code": "1234…", "url": "", "date": "…"}.

GET order?id=1002

همان ردیف فهرست به‌اضافه جزئیات؛ سفارش ناموجود: {"ok": false, "error": "سفارش پیدا نشد."}

{"ok": true, "data": { …ردیف فهرست…,
  "email": "", "shippingMethod": "پست پیشتاز", "shippingTotal": 50000, "discount": 0, "subtotal": 400000,
  "billing":  {"name": "سارا محمدی", "phone": "0912…", "state": "تهران", "city": "تهران", "address": "ونک…", "postcode": ""},
  "shipping": {"name": "…", "phone": "", "state": "…", "city": "…", "address": "…", "postcode": ""},
  "lines": [{"name": "شال نخی", "link": "…", "sku": "SH-1", "meta": "رنگ: آبی", "qty": 2, "unit": 200000, "total": 400000}],
  "notes": [{"id": 5, "text": "…", "customer": false, "by": "…", "date": "…"}],
  "carriers": {"post": "پست", "tipax": "تیپاکس", "chapar": "چاپار", "courier": "پیک", "other": "سایر"}}}

POST order-status

{"id": 1002, "status": "completed"}   →   {"ok": true, "id": 1002, "status": "completed"}

لغو سفارش باید موجودی کم‌شده را برگرداند (مثل ووکامرس).

۶. امکان‌های اختیاری

هر کدام را پیاده کردید، نامش را در features پاسخ ping بیاورید. شکل ورودی و خروجی همان افزونه وردپرس فروشیکس است؛ مهم‌ترین‌ها:

نام در featuresامکانعملیات‌ها
statsآمار داشبوردGET stats
trackingکد رهگیریPOST order-tracking
notesیادداشت سفارشPOST order-note
manual-ordersثبت سفارش دستیPOST order-create
products-editساخت و ویرایش محصولGET product POST product POST products-bulk POST media GET brands GET site-info
customersفهرست مشتریانGET customers
reportsگزارش فروش بازهGET report
visitsآمار بازدیدGET visits
couponsکد تخفیفGET coupons POST coupon POST coupons-bulk POST coupon-action
salesحراج گروهیGET sales POST sale-apply POST sale-clear
eventsاعلان سفارش تازه و موجودی کمGET events
historyتاریخچه تغییر قیمتGET history

POST order-tracking (tracking)

{"id": 1002, "carrier": "post", "code": "123456789", "complete": true}   →   {"ok": true, "data": {…جزئیات سفارش…}}

GET events?after=1001&low=5 (events)

برای اعلان سفارش تازه و موجودی کم (هر ۲ دقیقه). after=0 یعنی فقط maxOrderId را برگردان.

{"ok": true, "maxOrderId": 1003, "more": false,
 "orders": [ …ردیف کامل سفارش‌های با شناسه بزرگ‌تر از after (حداکثر ۵۰)… ],
 "lowStock": [{"id": 12, "parentId": 0, "name": "شال نخی", "qty": 2}]}

GET report?period=30d (reports)

period: month (ماه شمسی جاری)، prev_month، 30d، 90d، year (سال شمسی)، custom با from و to. فقط سفارش‌های فروش (پرداخت‌شده و لغونشده).

{"ok": true, "period": "30d", "label": "30 روز اخیر", "from": "2026-09-05", "to": "2026-10-04", "prevFrom": "…", "prevTo": "…",
 "summary": {"sales": 12500000, "orders": 31, "items": 58, "shipping": 900000, "discount": 300000, "gross": 12800000,
             "refunds": 300000, "feeDiscount": 0, "refundOther": 0, "avg": 403226},
 "prev": { …همان برای بازه قبل… },
 "daily": [{"day": "2026-09-05", "sales": 400000, "orders": 1}, …], "prevDaily": [ … ],
 "products": [{"id": 12, "parentId": 0, "name": "شال نخی", "qty": 9, "revenue": 1800000, "orders": 7}]}

GET customers (customers)

{"ok": true, "data": [{"key": "09121112233", "name": "سارا محمدی", "phone": "09121112233", "email": "", "state": "تهران",
  "city": "تهران", "orders": 4, "total": 1800000, "first": "2026-03-01T…", "last": "2026-10-04T…"}]}

برای جزئیات بقیه امکان‌ها (آمار داشبورد، محصول، کد تخفیف، حراج و…) کد افزونه وردپرس فروشیکس را ببینید یا با پشتیبانی تماس بگیرید.

۷. سنجش و اتصال

  1. در فروشیکس وارد شوید و ابزار سنجش اتصال را باز کنید؛ نشانی پایه و کلید را بدهید. امنیت امضا، شکل پاسخ هسته و امکان‌های اعلام‌شده بررسی می‌شود و هر ایراد با توضیح فارسی نشان داده می‌شود. هیچ داده‌ای روی سایت شما عوض نمی‌شود.
  2. وقتی همه موارد درست بود، فروشنده در «فروشگاه‌ها ← افزودن فروشگاه ← سایت دیگر (API)» نشانی و کلید را وارد می‌کند.
  3. اگر بعداً امکان تازه‌ای اضافه کردید، فروشنده دکمه «به‌روزرسانی امکان‌ها» را در فهرست فروشگاه‌ها می‌زند.

فروشگاه‌ساز هستید و می‌خواهید همه مشتری‌هایتان یک‌جا وصل شوند؟ با ما تماس بگیرید.