واجهة برمجية عامة تعمل مع أي موقع (Laravel أو ووكومرس أو غيرهما): طلبات الشراء من موقعك تُسجَّل فواتير في كاش بوس خلال ثوانٍ، وكميات الأصناف وأسعارها تتحدّث على موقعك لحظة تغيّرها في كاش بوس.
POST /orders، فيُسجَّل فاتورة بيع في كاش بوس بقيدها المحاسبي، ويُخصم المخزون من فرع الموقع، والمدفوع يدخل الخزنة، وغير المدفوع يُسجَّل على حساب العميل.GET /products، ثم اعتمد على التحديثات اللحظية. وبعد ضبط رابط الاستقبال تصلك الأصناف كلها أيضًا تدريجيًّا خلال دقائق، ثم تطابق دورية كل نصف ساعة ترسل أي اختلاف.kbs_) ورابط الواجهة الظاهرين في الشاشة.whsec_) ليرسله لك.رابط الواجهة:
https://csgmozibjjmqgwcwewnv.supabase.co/functions/v1/site-api/v1
.env)، ولا تضعه أبدًا في JavaScript المتصفح أو تطبيق جوال. الواجهة لا تقبل طلبات المتصفح أصلًا. وإذا تسرّب المفتاح، يغيّره صاحب الشركة من نفس الشاشة فيتوقف القديم فورًا.أرسل المفتاح في ترويسة Authorization مع كل طلب (أو في X-Api-Key):
Authorization: Bearer kbs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
429 ومعه Retry-After بالثواني.order_quota).402 بالكود order_limit_reached: احتفظ بالطلب وأعِد إرساله بنفس external_id لاحقًا، فيدخل بعد زيادة الحد أو مع بداية الشهر الجديد (details.resets_on).curl -H "Authorization: Bearer $KASHBOSS_KEY" \
https://csgmozibjjmqgwcwewnv.supabase.co/functions/v1/site-api/v1/ping
{"ok":true,"data":{"business_name":"شركتك","currency":"EGP","online_branch":"المخزن الرئيسي",
"orders_enabled":true,"push_enabled":true,
"order_quota":{"used":120,"limit":500,"remaining":380,"reached":false,"resets_on":"2026-11-01"},
"server_time":"2026-10-08T21:37:59+03:00"}}
النجاح: {"ok": true, "data": …}. والخطأ:
{"ok":false,"error":{"code":"total_mismatch","message":"…","message_ar":"…","details":{"expected":220,"received":230}}}
| HTTP | code | المعنى |
|---|---|---|
| 400 | invalid_request، invalid_json | جسم الطلب أو باراميتراته غير صحيحة |
| 401 | unauthorized | المفتاح غير موجود أو غير صحيح أو تم تغييره |
| 402 | feature_locked | اشتراك ربط المتجر الإلكتروني غير مفعّل على الحساب |
| 402 | order_limit_reached | وصلت الشركة إلى حدّ طلبات الشهر — احتفظ بالطلب وأعِد إرساله بنفس external_id لاحقًا |
| 403 | orders_disabled، connection_disabled | استقبال الطلبات موقوف من إعدادات الربط |
| 404 | not_found | مسار أو طلب أو صنف غير موجود |
| 409 | no_online_branch، conflict | لم يُحدَّد فرع الموقع، أو معرّف مربوط بصنف آخر |
| 409 | branch_unavailable | فرع البيع المربوط أُغلق أو لم يعد صالحًا — مؤقت: يغيّره صاحب الشركة من الإعدادات، احتفظ بالطلب وأعِد إرساله لاحقًا |
| 409 | invoice_missing | عند الإلغاء: فاتورة هذا الطلب لم تعد موجودة في كاش بوس (حُذفت) — لا تُعِد المحاولة، وراجع صاحب الشركة |
| 409 | no_webhook | عند POST /webhooks/test: لم يُضبط رابط الاستقبال في إعدادات الربط بعد |
| 413 | payload_too_large | الطلب أكبر من ٢٥٦ كيلوبايت |
| 422 | validation_failed، total_mismatch، tax_mismatch، currency_mismatch، variant_required، unknown_product | بيانات الطلب لا تُقبل — لا تُعِد المحاولة بنفس البيانات |
| 429 | rate_limited | تجاوزت الحد — انتظر Retry-After |
| 500 | server_error | خطأ مؤقت — أعِد المحاولة بنفس external_id |
401 (بعد تغيير المفتاح) و402 feature_locked و402 order_limit_reached و403 orders_disabled/connection_disabled و409 branch_unavailable و429 و5xx تزول بتدخّل صاحب الشركة أو بمرور الوقت، فاحتفظ بالطلب وأعِد إرساله لاحقًا بنفس external_id ولا تعتبره فاشلًا نهائيًّا. أمّا 400 و404 و422 فبياناتٌ لا تُقبل: راجعها ولا تكرّرها كما هي.كل طلب مرفوض يظهر لصاحب الشركة بسببه في «تقرير المتجر»، فيستطيع إخبارك بما حدث.
الكتالوج بالصفحات (حتى ٢٠٠ صنف في الصفحة). استخدمه للمزامنة الأولى، ولإعادة المطابقة الليلية إن أردت.
| باراميتر | الوصف |
|---|---|
limit | عدد الأصناف في الصفحة (الافتراضي ١٠٠، والأقصى ٢٠٠) |
cursor | قيمة next_cursor من الصفحة السابقة |
updated_since | الأصناف التي تغيّرت بعد وقت معيّن (ISO-8601) |
in_stock_only | 1 = المتوفّر فقط |
include_inactive | 1 = يشمل الأصناف الموقوفة |
{"ok":true,"next_cursor":"0e9c…","seq":18234,"data":[
{"product_id":"94e0…","sku":"TS-1","barcode":"622…","name":"تيشيرت قطن","description":null,
"category":"ملابس","brand":null,"image_url":"https://…","unit":"قطعة","unit_kind":"main","pack_note":null,
"price":250.00,"currency":"EGP","available_qty":12,"available_qty_exact":12.0,"in_stock":true,
"is_active":true,"has_variants":false,"variants":[],"external_id":null,"updated_at":"…"},
{"product_id":"23f6…","sku":"SHIRT","name":"قميص","has_variants":true,"in_stock":true,"available_qty":5,
"variants":[{"variant_id":"e9df…","sku":"SHIRT-L","name":"قميص — L / أزرق",
"attributes":{"size":"L","color":"أزرق"},"price":220.0,"available_qty":5,"in_stock":true}]}
]}
unit هي الوحدة التي يبيع بها موقعك (مثل «كرتونة» أو «قطعة»)، والكمية والسعر بهذه الوحدة. available_qty عدد صحيح من الوحدات الكاملة المتاحة، وavailable_qty_exact الكمية الدقيقة (مفيدة للأصناف بالوزن).has_variants: true) يُباع بمتغيّراته فقط، ولكل متغيّر سعره وكميته.available_qty: null وin_stock: true.كمية وسعر أصناف محدّدة حالًا (حتى ٢٠٠). يقبل أيضًا product_ids وvariant_ids. مفيد للتأكد من التوفّر لحظة إتمام الشراء.
يربط صنف كاش بوس بمعرّف الصنف عندك، ليصلك external_id في التحديثات. ويمكنك تثبيت وحدة البيع بـ unit_kind:
{"external_id":"55","external_variant_id":null,"unit_kind":"main"}
ولا يلزم ذلك عادةً: المطابقة بالكود (sku) تكفي، وكل طلب يحمل external_product_id يُنشئ الربط تلقائيًا.
أرسل الطلب عندما يصبح مؤكَّدًا على موقعك (بعد الدفع الإلكتروني، أو عند تأكيد طلب الدفع عند الاستلام).
{
"external_id": "10234",
"order_number": "#10234",
"currency": "EGP",
"customer": {"name": "أحمد علي", "phone": "01012345678", "email": "[email protected]",
"address": "١٠ شارع التحرير", "city": "القاهرة"},
"items": [
{"sku": "TS-1", "name": "تيشيرت قطن", "quantity": 2, "unit_price": 250.00, "external_product_id": "55"},
{"variant_id": "e9df…", "quantity": 1, "unit_price": 220.00}
],
"shipping": 50.00,
"discount": 0,
"tax_total": 0,
"prices_include_tax": true,
"total": 770.00,
"payment": {"status": "paid", "method": "card", "reference": "pi_3Nx…"},
"notes": "التوصيل بعد الخامسة"
}
| الحقل | الوصف |
|---|---|
external_id مطلوب | رقم الطلب عندك (حتى ١٠٠ حرف). مفتاح عدم التكرار: إرسال نفس الرقم مرة ثانية يرجع نفس الفاتورة ولا يُنشئ فاتورة جديدة — فأعِد المحاولة بأمان عند انقطاع الشبكة أو خطأ 500. |
items مطلوب | سطر لكل صنف، ويُحدَّد الصنف بأحد: variant_id أو product_id (من /products) أو sku (كود الصنف أو المتغيّر أو الباركود). وquantity وunit_price بوحدة البيع على الموقع. ويمكن إرسال unit = "main" أو "sub" للبيع بالوحدة الكبيرة أو الصغيرة صراحةً. |
total مطلوب | الإجمالي الذي دفعه العميل. يجب أن يساوي: مجموع (الكمية × السعر) − الخصم + الشحن (+ الضريبة إذا كانت الأسعار بدونها)، بفارق لا يزيد على ٠٫٠٥؛ وإلا يُرفض الطلب بـ total_mismatch. |
shipping، discount | الشحن يُسجَّل بندًا مستقلًا في الفاتورة، والخصم على مستوى الطلب. |
tax_total، prices_include_tax | إن كان موقعك يحسب ضريبة: أرسلها في tax_total (أو tax_amount لكل سطر). prices_include_tax (الافتراضي true) يعني أن أسعار السطور شاملة الضريبة. وإن لم يحسب موقعك ضريبة فلا ترسلها، وفي الشركات السعودية يحسب كاش بوس ضريبة القيمة المضافة تلقائيًّا من الإجمالي. |
currency | اختياري، ويجب أن يساوي عملة الشركة (يظهر في /ping)، وإلا يُرفض بـ currency_mismatch. |
payment.status | paid = مدفوع كاملًا (يدخل الخزنة) · cod أو unpaid = على حساب العميل · partial مع paid_amount = جزء مدفوع والباقي على الحساب. |
customer | يُطابَق العميل بالموبايل ثم بالإيميل، وإلا يُنشأ عميل جديد. وبدون موبايل ولا إيميل يُسجَّل على «عميل الموقع». |
product_id من الكتالوج.الرد 201 (أو 200 مع "duplicate": true للتكرار):
{"ok":true,"data":{"external_id":"10234","invoice_id":"fe7a…","invoice_number":"INV-00431","status":"recorded",
"duplicate":false,"total":770,"paid":770,"remaining":0,"payment_status":"paid","customer_id":"6970…",
"auto_created_products":[],"warnings":[],"journal_posted":true}}
التجربة بلا تسجيل: POST /orders?dry_run=1 ينفّذ كل التحقق والمطابقة ويرجع المعاينة (الأصناف ووحداتها والإجمالي) دون إنشاء أي فاتورة.
GET /orders/{external_id} يرجع الفاتورة وحالتها (recorded أو cancelled).
POST /orders/{external_id}/cancel بجسم اختياري {"reason":"…"}: يُسجَّل مرتجعًا كاملًا، فيرجع المخزون، ويُرَدّ المدفوع من الخزنة أو يُخصم من حساب العميل. والإلغاء المكرّر آمن.
جهّز على موقعك مسارًا يقبل POST بـ JSON، وأعطِ رابطه (يبدأ بـ https://) لصاحب الشركة ليحفظه. بعدها يصلك حدث inventory.updated مع كل تغيّر:
POST https://your-site.com/kashboss/webhook
X-KashBoss-Event: inventory.updated
X-KashBoss-Event-Id: evt_4ead176b55b04bc3b5c2f64fb02153f6
X-KashBoss-Timestamp: 1791484636
X-KashBoss-Signature: v1=41748c84231bed035543f62d3561a29d448db1a8df8a9a8e045cf187a3febfca
{"id":"evt_4ead…","type":"inventory.updated","created_at":"2026-10-08T21:38:05+03:00",
"data":{"seq":18240,"items":[
{"product_id":"94e0…","variant_id":null,"sku":"TS-1","barcode":"622…","external_id":"55",
"name":"تيشيرت قطن","unit":"قطعة","unit_kind":"main","price":250.00,"currency":"EGP",
"available_qty":11,"available_qty_exact":11.0,"in_stock":true,"is_active":true,"deleted":false,
"seq":18240,"updated_at":"…"}]}}
seq لكل صنف أو متغيّر، وتجاهل أي عنصر seq له أصغر أو يساوي المحفوظ (قد تصل التحديثات بترتيب مختلف عند إعادة المحاولة).seq (انظر «الترتيب»): تطبيق نفس القيم الكاملة مرتين لا يضر. لا تعتمد على X-KashBoss-Event-Id لمنع التكرار، فمعرّف الحدث يتغيّر مع كل إعادة محاولة للدفعة نفسها.301/302/307/308) وتُعدّ فشلًا. فأعطِ صاحب الشركة الرابط النهائي كما هو بعد كل التحويلات (مع www أو بدونها كما يعمل موقعك، وبـ https).2xx خلال ١٠ ثوانٍ (عالج العمل الثقيل في طابور). وأي رد آخر أو مهلة يُعاد بعد ١٠ ثوانٍ ثم بتأخير يتضاعف حتى ٣٠ دقيقة، ويصلك أحدث وضع عند العودة دون فقد شيء.410 Gone يوقف إرسال التحديثات حتى يعيد صاحب الشركة تشغيلها."deleted": true و"available_qty": 0.ping.التوقيع = HMAC-SHA256(سرّ التوقيع, timestamp + "." + الجسم الخام) بالنظام الست عشري. تحقّق منه على الجسم الخام قبل تحويله، وارفض الحدث إذا كان الوقت أبعد من ٥ دقائق. وعند تغيير السرّ تصل ترويسة فيها توقيعان مفصولان بفاصلة لمدة ٢٤ ساعة؛ اقبل الحدث إن طابق أيٌّ منهما.
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_KASHBOSS_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_KASHBOSS_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $ts . '.' . $raw, getenv('KASHBOSS_WEBHOOK_SECRET'));
$valid = false;
foreach (explode(',', $sig) as $part) {
if (hash_equals($expected, preg_replace('/^v1=/', '', trim($part)))) { $valid = true; }
}
if (!$valid || abs(time() - (int) $ts) > 300) { http_response_code(401); exit; }
const crypto = require('crypto');
function verify(rawBody, ts, header, secret) {
const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const ok = header.split(',').some(p => {
const v = p.trim().replace(/^v1=/, '');
return v.length === expected.length && crypto.timingSafeEqual(Buffer.from(v), Buffer.from(expected));
});
return ok && Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
}
import hmac, hashlib, time
def verify(raw: bytes, ts: str, header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw, hashlib.sha256).hexdigest()
ok = any(hmac.compare_digest(p.strip().removeprefix("v1="), expected) for p in header.split(","))
return ok and abs(time.time() - int(ts)) <= 300
# .env
KASHBOSS_API_URL=https://csgmozibjjmqgwcwewnv.supabase.co/functions/v1/site-api/v1
KASHBOSS_API_KEY=kbs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
KASHBOSS_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// config/services.php
'kashboss' => [
'url' => env('KASHBOSS_API_URL'),
'key' => env('KASHBOSS_API_KEY'),
'webhook_secret' => env('KASHBOSS_WEBHOOK_SECRET'),
],
// app/Services/KashBoss.php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class KashBoss
{
private function http()
{
return Http::baseUrl(config('services.kashboss.url'))
->withToken(config('services.kashboss.key'))
->acceptJson()
->timeout(30)
// إعادة المحاولة عند انقطاع الشبكة أو 429/5xx فقط — آمنة بفضل external_id
->retry(3, 2000, fn ($e) => !($e instanceof \Illuminate\Http\Client\RequestException)
|| in_array($e->response->status(), [429, 500, 502, 503, 504]), throw: false);
}
/** هل البوابة جاهزة لاستقبال الطلبات الآن؟ (المفتاح سليم، الاستقبال شغّال، والحد لم يمتلئ) */
public function ready(): bool
{
$res = $this->http()->get('/ping')->json() ?? [];
return ($res['ok'] ?? false) === true
&& ($res['data']['orders_enabled'] ?? false) === true
&& !($res['data']['order_quota']['reached'] ?? false);
}
public function products(?string $cursor = null): array
{
return $this->http()->get('/products', ['limit' => 200, 'cursor' => $cursor])->json() ?? [];
}
public function stock(array $skus): array
{
return $this->http()->get('/stock', ['skus' => implode(',', $skus)])->json() ?? [];
}
public function sendOrder(array $order): array
{
return $this->http()->post('/orders', $order)->json() ?? [];
}
public function cancelOrder(string $externalId, string $reason = ''): array
{
return $this->http()->post('/orders/' . rawurlencode($externalId) . '/cancel', ['reason' => $reason])->json() ?? [];
}
}
// app/Jobs/SendOrderToKashBoss.php
namespace App\Jobs;
use App\Models\Order;
use App\Services\KashBoss;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
class SendOrderToKashBoss implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public $tries = 10;
public $backoff = [10, 30, 60, 300, 900];
public function __construct(public Order $order) {}
public function handle(KashBoss $kashboss): void
{
$o = $this->order->load('items', 'customer');
$res = $kashboss->sendOrder([
'external_id' => (string) $o->id,
'order_number' => $o->number,
// 'currency' اختياري: اتركه فارغًا ليأخذ عملة الشركة (أو مرّر عملتها من GET /ping)
'customer' => [
'name' => $o->customer->name,
'phone' => $o->customer->phone,
'email' => $o->customer->email,
'address' => $o->shipping_address,
'city' => $o->shipping_city,
],
'items' => $o->items->map(fn ($i) => [
'sku' => $i->sku,
'name' => $i->name,
'quantity' => $i->quantity,
'unit_price' => $i->price,
'external_product_id' => (string) $i->product_id,
])->values()->all(),
'shipping' => $o->shipping_total,
'discount' => $o->discount_total,
'total' => $o->grand_total,
'payment' => [
'status' => $o->is_paid ? 'paid' : 'cod',
'method' => $o->payment_method,
'reference' => $o->payment_reference,
],
]);
if (($res['ok'] ?? false) === true) {
$o->update(['kashboss_invoice' => $res['data']['invoice_number'], 'kashboss_status' => null]);
return;
}
$code = $res['error']['code'] ?? 'server_error';
// أخطاء تزول بتدخّل صاحب الشركة أو بمرور الوقت (حدّ الشهر · الوحدة غير مفعّلة · المفتاح اتغيّر ·
// الاستقبال موقوف · الفرع مغلق) ⇒ الطلب محفوظ عندك ويُعاد إرساله من الجدولة تحت، بلا فشل نهائي
if (in_array($code, ['order_limit_reached', 'feature_locked', 'unauthorized', 'orders_disabled',
'connection_disabled', 'branch_unavailable', 'no_online_branch'])) {
$o->update(['kashboss_status' => 'waiting_kashboss']);
return;
}
if (in_array($code, ['server_error', 'rate_limited'])) {
$this->release(60); // مؤقت ⇒ إعادة بنفس external_id
} else {
logger()->error('KashBoss rejected order', ['order' => $o->id, 'error' => $res['error'] ?? null]);
$this->fail(); // بيانات لا تُقبل ⇒ راجعها ولا تكرّرها كما هي
}
}
}
// عند تأكيد الطلب (بعد الدفع أو عند تأكيد الدفع عند الاستلام):
SendOrderToKashBoss::dispatch($order);
// routes/console.php (أو Kernel::schedule) — الطلبات المنتظرة (حدّ الشهر أو إعداد يحتاج صاحب الشركة):
// تحقّق من GET /ping أولًا حتى لا تمتلئ سجلات «تقرير المتجر» بمحاولات ستُرفض حتمًا.
Schedule::call(function () {
if (!app(\App\Services\KashBoss::class)->ready()) {
return;
}
Order::where('kashboss_status', 'waiting_kashboss')
->each(fn ($o) => SendOrderToKashBoss::dispatch($o));
})->hourly();
// routes/api.php (مسارات api بلا CSRF)
use App\Http\Controllers\KashBossWebhookController;
Route::post('/kashboss/webhook', KashBossWebhookController::class);
routes/api.php افتراضيًّا؛ أنشئه بالأمر php artisan install:api. ومسارات هذا الملف تحمل البادئة /api تلقائيًّا، فرابط الاستقبال الذي تعطيه لصاحب الشركة هو https://your-site.com/api/kashboss/webhook (وليس /kashboss/webhook). تأكّد أنه يرد مباشرة دون تحويل (مثل إضافة شرطة أخيرة أو الانتقال من http إلى https).// app/Http/Controllers/KashBossWebhookController.php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class KashBossWebhookController
{
public function __invoke(Request $request)
{
$raw = $request->getContent();
$ts = $request->header('X-KashBoss-Timestamp', '');
$sig = $request->header('X-KashBoss-Signature', '');
$expected = hash_hmac('sha256', $ts . '.' . $raw, config('services.kashboss.webhook_secret'));
$valid = collect(explode(',', $sig))
->contains(fn ($p) => hash_equals($expected, preg_replace('/^v1=/', '', trim($p))));
abort_unless($valid && abs(time() - (int) $ts) <= 300, 401);
// لا تعتمد على X-KashBoss-Event-Id لمنع التكرار (يتغيّر مع كل إعادة محاولة)؛
// الحماية هي مقارنة seq لكل صنف أدناه.
$event = json_decode($raw, true);
if (($event['type'] ?? '') === 'inventory.updated') {
foreach ($event['data']['items'] as $item) {
// صنف بلا كود (null): where('sku', null) كان يحدّث أول صنف عندك بلا كود!
$product = !empty($item['sku'])
? Product::where('sku', $item['sku'])->first()
: (!empty($item['external_id']) ? Product::find($item['external_id']) : null);
if (!$product || ($product->kashboss_seq ?? 0) >= $item['seq']) {
continue; // صنف غير موجود عندك أو تحديث أقدم
}
$product->update([
'stock' => $item['deleted'] ? 0 : ($item['available_qty'] ?? $product->stock),
'price' => $item['price'] ?? $product->price,
'is_active' => $item['is_active'] && !$item['deleted'],
'kashboss_seq' => $item['seq'],
]);
}
}
return response()->noContent(); // 204 خلال ثوانٍ
}
}
أضف عمود kashboss_seq (bigint) لجدول الأصناف لحفظ ترتيب التحديثات. وللأصناف ذات المقاسات طابِق sku المتغيّر بجدول المتغيّرات عندك.
// app/Console/Commands/KashBossSync.php → php artisan kashboss:sync
public function handle(\App\Services\KashBoss $kashboss)
{
$cursor = null;
do {
$page = $kashboss->products($cursor);
foreach ($page['data'] as $p) {
// أنشئ أو حدّث الصنف عندك بـ $p['sku'] و$p['price'] و$p['available_qty'] و$p['variants']
}
$cursor = $page['next_cursor'] ?? null;
} while ($cursor);
}
woocommerce_order_status_processing (وللدفع عند الاستلام من woocommerce_order_status_on-hold أو حسب إعدادك) بـ wp_remote_post وبنفس شكل الطلب أعلاه، ومع external_id = رقم الطلب.woocommerce_order_status_cancelled إلى /orders/{id}/cancel.register_rest_route)، وتحقّق من التوقيع بمثال PHP، ثم طبّق الكمية بـ wc_update_product_stock والسعر بـ $product->set_regular_price()..env على الخادم فقط.GET /ping يرجع اسم الشركة والعملة الصحيحة.GET /products).?dry_run=1 وراجع المعاينة.2xx سريعًا، و«إرسال حدث تجريبي» ينجح.external_id في كل محاولة.order_limit_reached · feature_locked · 401 بعد تغيير المفتاح · branch_unavailable) لا يُحذف ولا يُعدّ فاشلًا، ويُعاد إرساله تلقائيًّا بعد أن يرد GET /ping بالجاهزية./api إن كان في routes/api.php.للاستفسار التقني تواصل مع فريق كاش بوس عن طريق صاحب الشركة.