treez
واجهة تريز v1

ازرع أشجار من صفحة الدفع.

طلب HTTPS واحد لكل طلب. ويب هوك موقّع لما تنزرع الأشجار. وتكامل جاهز مع المنصات اللي تستخدمها.

نظرة عامة#

تريز يعطي عملاءك نقاطاً على مشترياتهم، وكل 100 نقطة تزرع شجرة محلية حقيقية موثّقة بالـGPS. فيه طريقتين ترسل لنا فيها الطلبات — اختر اللي يناسب متجرك:

الرابط الأساسي: https://api.treezplus.com/v1. البيانات بصيغة JSON، والحقول بنمط camelCase، والأوقات بصيغة ISO-8601 بتوقيت UTC. القوائم تستخدم ?limit=&cursor= وترجع { items, nextCursor }.

النقاط تبدأ معلّقة
نقاط الطلبات تنتظر فترة (افتراضياً 14 يوم) قبل ما توصل محفظة العميل. الاسترجاع والإلغاء خلال هالفترة يعكسها وما يكلفك شي.

المصادقة#

أنشئ مفاتيح API من بوابة المتجر في المطوّرون ← مفاتيح API. أرسل المفتاح كـ Bearer من خادمك:

HTTP
Authorization: Bearer sk_live_4f8a…
المفتاحوش يسوي
sk_test_…الطلبات تُسجَّل بـ livemode: false وتطلق الويب هوك، بس ما تلمس ميزانيتك ولا محافظ العملاء. متاح وقت ما متجرك بانتظار الموافقة.
sk_live_…طلبات حقيقية ونقاط حقيقية. يحتاج متجراً معتمداً.
خلّ المفاتيح سرّية
لا تحط المفتاح في متصفح أو تطبيق جوال أو مستودع عام. نحفظ نسخة مشفّرة فقط، فالمفتاح الضائع ما ينعرض مرة ثانية — ألغه وأنشئ واحد جديد. الحد: 600 طلب بالدقيقة لكل مفتاح (429 RATE_LIMITED مع Retry-After).

واجهة الطلبات#

أرسل الطلب لما ينْدفع (أو يكتمل — حسب اختيارك في الإعدادات ← قواعد النقاط). إرسال نفس externalOrderId مرة ثانية يحدّث الطلب بدل ما يكرره.

POST/v1/orders
curl
curl -X POST https://api.treezplus.com/v1/orders \
  -H "Authorization: Bearer sk_test_…" \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "externalOrderId": "1001",
    "amount": 12.5,
    "currency": "OMR",
    "status": "paid",
    "customer": { "email": "salim@example.com", "name": "Salim", "phone": "+96890000001" },
    "occurredAt": "2026-10-24T09:30:00Z"
  }'

حقول الطلب

externalOrderId
string
رقم الطلب عندك. فريد لكل متجر.
amount
number
إجمالي الطلب بالوحدة الكبيرة (12.5 = 12.500 ر.ع).
currency
string
OMR · SAR · AED · KWD · QAR · BHD · USD
status
"paid" | "completed"
حالة الطلب الحالية.
customer
object
email (أرسله دائماً — الحقل الوحيد اللي نعرف فيه عضو تريز)، name، phone (اختياري، يُحفظ لسجلاتك وما يُستخدم للمطابقة). شوف مطابقة العملاء.
occurredAt
تاريخ ISO، اختياري
وقت الطلب. افتراضياً الآن.

الاستجابة

200 OK
{
  "id": "6f1c2a7e-0b7d-4c55-9a43-3f0d2a9b1e10",
  "source": "api",
  "externalOrderId": "1001",
  "livemode": true,
  "amount": 12.5,
  "currency": "OMR",
  "status": "paid",
  "customer": {
    "email": "salim@example.com",
    "phone": "+96890000001",
    "name": "Salim",
    "trees": { "matched": true, "firstName": "Salim" }
  },
  "points": 125,
  "pointsStatus": "pending",
  "skipReason": null,
  "confirmAt": "2026-11-07T09:30:00.000Z",
  "confirmedAt": null,
  "reversedAt": null,
  "createdAt": "2026-10-24T09:30:00.000Z",
  "updatedAt": "2026-10-24T09:30:00.000Z"
}

النقاط = floor(amount × pointsPerUnit) حسب عملة الطلب، بحد أقصى حسب إعدادك. ما فيه قاعدة للعملة أو المبلغ أقل من الحد الأدنى ← points: 0 مع skipReason.

دورة الحياة

  1. pending

    النقاط محجوزة من ميزانيتك؛ confirmAt = وقت الطلب + أيام الانتظار.

  2. confirmed

    انتهت فترة الانتظار والعميل في تريز ← انضافت النقاط.

  3. reversed

    انلغى أو استُرجع قبل التأكيد ← رجعت الميزانية.

العميل لسه مو في تريز؟ النقاط تنتظر لحد 90 يوم وتنضاف تلقائياً لما يدخل تطبيق تريز بنفس البريد.

تحديث الحالة

POST/v1/orders/:externalOrderId/status
curl
curl -X POST https://api.treezplus.com/v1/orders/1001/status \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "status": "refunded" }'

الحالات: completed، cancelled، refunded. الاسترجاع بعد التأكيد ينسجّل، بس النقاط ما تنسحب.

القائمة والتفاصيل

GET/v1/orders?pointsStatus&source&limit&cursor
GET/v1/orders/:id
curl
curl "https://api.treezplus.com/v1/orders?pointsStatus=pending&limit=20" \
  -H "Authorization: Bearer sk_live_…"

مطابقة العملاء#

النقاط تروح لحساب تريز اللي بريده يطابق customer.email في الطلب. العملاء والمزارعون يدخلون تطبيق تريز برمز لمرة وحدة يوصلهم على البريد، فالبريد هو الهوية اللي نعتمد عليها. أرسل customer.email دائماً.

customer.email
نص · مطلوب للنقاط
يُطابق بدون حساسية لحالة الأحرف (بعد حذف المسافات وتحويله لأحرف صغيرة) مع حسابات العملاء والمزارعين.
customer.phone
نص · اختياري
يُحفظ ويظهر لك في البوابة. ما يُستخدم للمطابقة أبداً — أرقام الجوال في تريز غير موثّقة.
customer.name
نص · اختياري
يظهر في بوابتك.
بدون بريد، بدون نقاط
الطلب بدون customer.email ينسجّل بـ pointsStatus: "skipped" و skipReason: "NO_CUSTOMER_CONTACT" — هالنقاط ما أحد يقدر يستلمها، فما ينحجز شي من ميزانيتك. إرسال رقم الجوال بس يُعتبر بدون بريد.

العميل لسه مو في تريز

إذا ما فيه حساب بهالبريد، الاستجابة تبيّن trees.matched: false والنقاط تنتظر لحد 90 يوم. تنضاف أول ما أحد يدخل تطبيق تريز بنفس البريد (وتتأكد فوراً إذا انتهت فترة الانتظار). غير كذا تنتهي بحالة unclaimed_expired وترجع لميزانيتك. طلبات وضع التجربة ما تُطابق مع عملاء حقيقيين أبداً.

أسباب التخطي

skipReasonالمعنى
NO_CUSTOMER_CONTACTما فيه بريد للعميل في الطلب، فما فيه أحد نعطيه النقاط.
NO_RULE_FOR_CURRENCYما فيه قاعدة نقاط لهذه العملة.
BELOW_MINIMUMأقل من الحد الأدنى للطلب.
ZERO_POINTSمبلغ الطلب صغير وما يكسب نقطة كاملة.
INSUFFICIENT_BUDGETما كانت الميزانية كافية لما وصل الطلب.
AWAITING_STATUSبانتظار اكتمال الطلب (قاعدة النقاط عندك تعطي عند الاكتمال).
CANCELLED_BEFORE_AWARDانلغى قبل ما يكسب نقاط.
MERCHANT_NOT_ACTIVEمتجرك ما كان معتمد لما وصل الطلب.

عدم التكرار#

الشبكات تفشل أحياناً. أرسل ترويسة Idempotency-Key (مثلاً order-1001) وأعد المحاولة بأمان: نفس المفتاح يرجع نفس الاستجابة مع Idempotent-Replayed: true، وما يضيف نقاط مرتين. استخدام نفس المفتاح مع محتوى مختلف يرجع 409 IDEMPOTENCY_KEY_REUSED.

حتى بدون الترويسة، الطلبات تُحدَّث حسب (المتجر، المصدر، externalOrderId).

الأخطاء#

الأخطاء تستخدم حالة HTTP ورمزاً ثابتاً:

4xx
{
  "error": {
    "code": "MERCHANT_NOT_ACTIVE",
    "message": "Your store is not approved yet",
    "details": {}
  }
}
الرمزHTTPالمعنى
VALIDATION_ERROR400حقل ناقص أو غير صحيح — شوف details.issues.
INVALID_API_KEY401المفتاح غلط أو ملغى أو مو موجود.
UNAUTHORIZED401ما انرسلت بيانات دخول.
MERCHANT_NOT_ACTIVE403متجرك لسه ما انعتمد (المفاتيح الحقيقية والنقاط الحقيقية).
TEST_MODE_UNSUPPORTED403مفتاح تجربة استدعى نقطة تشتغل بالوضع الحقيقي فقط.
ORDER_NOT_FOUND404ما فيه طلب بهذا المعرّف لمتجرك.
IDEMPOTENCY_KEY_REUSED409نفس Idempotency-Key مع محتوى مختلف.
INSUFFICIENT_BUDGET409الميزانية ما تكفي (الطلب ينحفظ كمتجاوز).
RATE_LIMITED429طلبات كثيرة — انتظر عدد ثواني Retry-After.
INTERNAL500صار خلل عندنا. أعد المحاولة بنفس Idempotency-Key.

الويب هوك#

أضف نقطة في المطوّرون ← الويب هوك وتريز بيرسل لها أحداث JSON بطريقة POST — من الطلبات لين انزراع الشجرة. كل حدث يستخدم نفس الغلاف:

POST https://your-server/treez/webhooks
{
  "id": "evt_01JB2Q8M4K7Y3ZP6",
  "type": "tree.planted",
  "createdAt": "2026-10-24T09:30:00.000Z",
  "livemode": true,
  "merchantId": "b2c1…",
  "data": {
    "tree": { "id": "…", "status": "planted", "species": { "nameEn": "Ghaf" }, "…": "…" },
    "passportUrl": "https://treez.om/t/ghaf-7k4p",
    "fundingShare": 0.35
  }
}

الإرسال وإعادة المحاولة

  • رد بأي 2xx خلال 10 ثوانٍ، وخلّ الشغل الثقيل في مهمة خلفية.
  • الإرسال الفاشل يُعاد بعد 1m · 5m · 30m · 2h · 6h · 12h · 24h (7 محاولات).
  • النقطة اللي تفشل كل إرسالياتها لمدة 3 أيام تتعطّل تلقائياً. فعّلها من البوابة.
  • الأحداث ممكن توصل أكثر من مرة أو بغير ترتيب — تجاهل المكرر حسب id.

أنواع الأحداث

الحدثمتى
order.points_pendingطلب كسب نقاطاً صارت معلّقة.
order.points_confirmedانتهت فترة الانتظار وانضافت النقاط.
order.points_reversedطلب انلغى أو استُرجع قبل التأكيد.
order.points_skippedطلب ما كسب نقاط (بدون بريد للعميل، أو بدون قاعدة، أو أقل من الحد، أو الميزانية).
order.refunded_after_confirmationطلب استُرجع بعد تأكيد نقاطه.
tree.readyشجرة موّلها عملاؤك جاهزة للزراعة.
tree.scheduledالشجرة صار لها موعد زراعة.
tree.plantedانزرعت، مع صورة وموقع GPS.
tree.verifiedمراجع وثّق أدلة الزراعة.
claim_code.claimedعميل استخدم واحد من رموزك.
award.createdأعطيت عميلاً نقاطاً عند الكاشير.
merchant.approvedتريز اعتمدت متجرك.
budget.lowميزانية نقاطك قاربت تخلص.
pingحدث تجريبي ترسله من البوابة.

أحداث order.* تحمل { order }؛ وأحداث tree.* تحمل { tree, passportUrl, fundingShare } وتوصل بس للمتاجر اللي موّلت الشجرة.

التحقق من التوقيع#

كل طلب يحمل ترويسة توقيع:

HTTP
Treez-Signature: t=1761298200,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
  1. قسّم الترويسة على ,؛ واقرأ t (ثواني يونكس) وكل قيمة v1.
  2. احسب HMAC-SHA256(secret, t + "." + rawBody) بصيغة hex.
  3. اقبل إذا ساوى أي قيمة v1 (مقارنة بوقت ثابت) وكان t أحدث من 5 دقائق.
تغيير السر
بعد تغيير السر نرسل التوقيعين لمدة 24 ساعة (v1=new,v1=old)، فتقدر تنشر السر الجديد بدون ما تضيع أحداث.
Node.js
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.TREEZ_WEBHOOK_SECRET; // "whsec_…"

// Keep the raw body: the signature covers the exact bytes we sent.
app.post("/treez/webhooks", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("Treez-Signature") ?? "";
  const parts = header.split(",").map((p) => p.trim().split("="));
  const t = parts.find(([k]) => k === "t")?.[1];
  const signatures = parts.filter(([k]) => k === "v1").map(([, v]) => v);

  // Reject old timestamps (replay protection).
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.status(400).send("stale");

  const expected = crypto.createHmac("sha256", SECRET).update(`${t}.`).update(req.body).digest("hex");
  const valid = signatures.some(
    (s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)),
  );
  if (!valid) return res.status(400).send("bad signature");

  const event = JSON.parse(req.body.toString("utf8"));
  switch (event.type) {
    case "order.points_confirmed":
      // event.data.order.points were credited to the customer
      break;
    case "tree.planted":
      // event.data.passportUrl — share it with your customer!
      break;
  }
  res.sendStatus(200); // answer fast; do slow work in a queue
});

المنصات#

كل منصة عبارة عن محوّل يحوّل طريقة تثبيتها والويب هوك حقها لنفس شكل الطلب الموحّد — فالنقاط وفترة الانتظار والاسترجاع والويب هوك تشتغل بنفس الطريقة في كل مكان.

سلة
ثبّت تطبيق تريز من متجر تطبيقات سلة، وبعدها اكتب رمز الربط الظاهر في بوابة تريز.
زد
اضغط ربط في البوابة ووافق على تريز في زد (OAuth). الطلبات تتزامن تلقائياً.
ووكومرس
ووكومرس ← الإعدادات ← متقدم ← Webhooks ← إضافة. الموضوع: Order updated. الصق الرابط والسر من البوابة.
شوبيفاي
اكتب نطاق myshopify.com وافق على تطبيق تريز (OAuth).
موقع آخر
أي شي ثاني — موقعك أو تطبيقك أو نظام الكاشير: استخدم واجهة الطلبات أعلاه.

توكنات المنصات تُحفظ مشفّرة. حذف التطبيق من المنصة يفصله من تريز. تبي منصة ثانية؟ إضافتها محوّل واحد عندنا — راسلنا على hello@treez.om.

وضع التجربة#

  • استخدم مفتاح sk_test_: الطلبات تُحفظ بـ livemode: false، وتظهر في البوابة بشارة تجربة وتطلق الويب هوك — بدون تغيير الميزانية أو المحافظ.
  • اضغط أرسل اختبار على أي نقطة عشان يوصلك حدث ping موقّع وتشوف الاستجابة في سجل الإرسال.
  • مفاتيح التجربة ما تقدر تنشئ رموز مطالبة أو تعطي نقاط (TEST_MODE_UNSUPPORTED).
  • محلياً، استخدم نفق (مثل ngrok) لنقطتك — نقاط الإنتاج لازم تكون HTTPS.
جاهز تزرع؟

سجّل، وخذ مفتاح تجربة، وأرسل أول طلب خلال خمس دقائق.

سجّل متجرك