API وWebhooks: دمج TenancyDesk مع أنظمتك

محدّث 14 يوليو 2026

REST API على مستوى المؤسسات وwebhooks في الوقت الفعلي تمكّن التكامل السلس بين TenancyDesk وأنظمة عملك الحالية. قم ببناء سير عمل مخصص، أتمتة مزامنة البيانات، وإنشاء تكاملات قوية.

نظرة عامة على API

البنية المعمارية

RESTful API يتبع معايير الصناعة:

  • URLs قائمة على الموارد (/deals, /parties, /documents)
  • أساليب HTTP: GET, POST, PUT, PATCH, DELETE
  • أجسام طلبات/استجابات JSON
  • رموز حالة HTTP القياسية
  • مواصفات OpenAPI 3.0 متاحة

Base URL: https://api.tenancydesk.com/v1/

وثائق API: https://docs.tenancydesk.com/api (Swagger UI تفاعلي)


المصادقة

API Keys (موصى به)

توليد مفتاح API:

  1. الإعداداتالتكاملاتAPI Keys
  2. انقر توليد مفتاح API جديد
  3. الاسم: "Production Integration" (وصفي)
  4. النطاقات: حدد الأذونات (read:deals, write:parties، إلخ)
  5. انسخ المفتاح فوراً (يُعرض مرة واحدة فقط)

عنوان المصادقة:

curl -H "Authorization: Bearer sk_live_abc123xyz..." \
  https://api.tenancydesk.com/v1/deals

الأمان:

  • تخزين آمن (متغيرات البيئة، ليس الكود)
  • تدوير كل 90 يوماً
  • استخدم مفاتيح مختلفة لـ dev/staging/prod
  • إلغاء فوري إذا تم الاختراق

JWT Bearer Tokens (OAuth 2.0 - Enterprise)

لعمليات سياق المستخدم:

  1. احصل على رمز الوصول عبر OAuth flow
  2. ضمّنه في عنوان Authorization
  3. انتهاء الرمز: ساعة واحدة (رمز التحديث: 7 أيام)

استخدم عندما: بناء تطبيقات حيث يصادق المستخدمون بحسابات TenancyDesk الخاصة بهم


نقاط API الأساسية

Deals API

قائمة جميع الصفقات:

GET /v1/deals?status=active&limit=50&offset=0

Response 200:
{
  "data": [
    {
      "id": "deal_abc123",
      "property_address": "Unit 1205, Churchill Tower, Business Bay",
      "tenant_name": "أحمد محمد",
      "annual_rent": 85000,
      "status": "active",
      "ejari_number": "12345678",
      "created_at": "2025-01-15T10:30:00Z"
    }
  ],
  "pagination": {
    "total": 127,
    "limit": 50,
    "offset": 0,
    "has_more": true
  }
}

إنشاء صفقة:

POST /v1/deals
Content-Type: application/json

{
  "property_address": "Unit 1205, Churchill Tower",
  "tenant": {
    "name": "أحمد محمد",
    "emirates_id": "784-1988-1234567-1",
    "mobile": "+971501234567"
  },
  "annual_rent": 85000,
  "start_date": "2025-02-01",
  "payment_schedule": "4_cheques"
}

Response 201:
{
  "data": {
    "id": "deal_abc123",
    "status": "draft",
    ...
  }
}

الحصول على تفاصيل الصفقة:

GET /v1/deals/{deal_id}

Response 200: كائن الصفقة الكامل مع الأطراف والمستندات والمدفوعات المتداخلة

تحديث صفقة:

PATCH /v1/deals/{deal_id}

{
  "annual_rent": 90000,
  "status": "active"
}

Parties API

إنشاء مستأجر:

POST /v1/parties/tenants

{
  "name": "فاطمة علي",
  "emirates_id": "784-1990-2345678-2",
  "mobile": "+971509876543",
  "email": "fatima@email.com"
}

البحث عن الأطراف:

GET /v1/parties?search=أحمد&type=tenant&limit=20

Documents API

رفع مستند:

POST /v1/deals/{deal_id}/documents
Content-Type: multipart/form-data

file: @emirates-id-front.pdf
category: tenant_emirates_id

Response 201:
{
  "data": {
    "id": "doc_xyz789",
    "category": "tenant_emirates_id",
    "filename": "emirates-id-front.pdf",
    "extracted_data": {
      "name": "عمر محمد خالد",
      "id_number": "784-1988-1234567-1",
      "expiry_date": "2028-12-31"
    },
    "verification_status": "verified"
  }
}

Payments API

قائمة جدول المدفوعات:

GET /v1/deals/{deal_id}/payments

Response: مصفوفة من أقساط الدفع مع تواريخ الاستحقاق والمبالغ والحالة

تحديد الدفع كمستلم:

PATCH /v1/payments/{payment_id}

{
  "status": "paid",
  "paid_date": "2025-02-01",
  "transaction_ref": "CHQ-12345"
}

حدود المعدل

وصول API متاح فقط لخطة Enterprise. حدود المعدل الافتراضية:

الخطةطلبات/دقيقةطلبات/ساعةحد الاندفاع
Enterprise30015,000600

عناوين حد المعدل (تُرجع في كل استجابة):

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1640000000

429 Too Many Requests:

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "تم تجاوز حد المعدل. أعد المحاولة بعد 60 ثانية.",
    "retry_after": 60
  }
}

أفضل الممارسات: نفذ exponential backoff عند تلقي 429


Webhooks

نظرة عامة

إشعارات في الوقت الفعلي عند حدوث أحداث في TenancyDesk. لا يُطلب polling.

ضمان التسليم: تسليم مرة واحدة على الأقل مع إعادة محاولات تلقائية

التحقق من التوقيع: HMAC-SHA256 للأمان

إعداد Webhook

1. إنشاء نقطة نهاية webhook (خادمك):

# مثال Flask
from flask import Flask, request
import hmac
import hashlib

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    # التحقق من التوقيع
    signature = request.headers.get('X-TenancyDesk-Signature')
    payload = request.data

    # حساب التوقيع المتوقع
    secret = 'your_webhook_secret'
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    if signature != expected:
        return 'توقيع غير صالح', 401

    # معالجة الحدث
    event = request.json
    if event['type'] == 'payment.overdue':
        send_reminder(event['data'])

    return 'OK', 200

2. تسجيل webhook في TenancyDesk:

POST /v1/webhooks

{
  "url": "https://your-domain.com/webhook",
  "events": ["payment.overdue", "deal.status_changed"],
  "description": "Webhook للإنتاج لتذكيرات الدفع"
}

Response 201:
{
  "data": {
    "id": "wh_abc123",
    "url": "https://your-domain.com/webhook",
    "secret": "whsec_xyz789...",  // استخدم للتحقق من التوقيع
    "events": ["payment.overdue", "deal.status_changed"],
    "status": "active"
  }
}

أحداث Webhook

يُصدر TenancyDesk 21 نوعًا من الأحداث عبر ست فئات.

أحداث الصفقة (5):

  • deal.created - تم إنشاء صفقة جديدة
  • deal.updated - تغيرت تفاصيل الصفقة
  • deal.status_changed - تغيّرت حالة الصفقة (مثل الانتقال إلى نشطة)
  • deal.completed - تم إكمال الصفقة
  • deal.cancelled - تم إلغاء الصفقة

أحداث الدفع (4):

  • payment.created - تم إنشاء دفعة في جدول السداد
  • payment.received - تم تحديد الدفع كمدفوع
  • payment.overdue - فات تاريخ استحقاق الدفع
  • payment.bounced - ارتد الشيك

أحداث المستندات (4):

  • document.uploaded - تمت إضافة مستند جديد
  • document.verified - تم التحقق من المستند
  • document.rejected - فشل التحقق
  • document.expiring - المستند على وشك الانتهاء

أحداث الأطراف (3):

  • party.created - تمت إضافة طرف (مستأجر أو مالك)
  • party.updated - تغيرت بيانات الطرف
  • party.kyc_completed - اكتمل التحقق من هوية الطرف (KYC)

أحداث المهام (3):

  • task.created - تم إنشاء مهمة
  • task.completed - تم إكمال المهمة
  • task.overdue - تجاوزت المهمة تاريخ استحقاقها

أحداث الامتثال (2):

  • compliance.issue_created - تم اكتشاف مشكلة امتثال
  • compliance.issue_resolved - تم حل مشكلة الامتثال

لا توجد أحداث webhook مخصصة لتسجيل إيجاري/توثيق — لا يتكامل TenancyDesk مباشرةً مع دائرة الأراضي والأملاك (DLD). عندما يسجّل فريقك رقم التسجيل أو يحدّث حالة تسجيل الصفقة، يُسلَّم هذا التغيير عبر حدث deal.updated المذكور أعلاه.

هيكل Webhook Payload

الغلاف القياسي:

{
  "id": "evt_abc123",
  "type": "payment.overdue",
  "created_at": "2025-12-26T10:30:00Z",
  "data": {
    "deal_id": "deal_xyz789",
    "payment_id": "pay_123",
    "tenant_name": "أحمد محمد",
    "amount": 21250,
    "due_date": "2025-01-01",
    "cheque_number": "CHQ-001"
  },
  "company_id": "comp_abc"
}

منطق إعادة المحاولة

TenancyDesk يتبع معيار Hook0 الصناعي:

إعادات محاولة سريعة (أول 10 محاولات):

  • المحاولة 1: فوري
  • المحاولة 2: 5 ثوانٍ
  • المحاولة 3: 25 ثانية
  • المحاولة 4: 125 ثانية (2 دقيقة)
  • المحاولات 5-10: exponential backoff حتى 5 دقائق

إعادات محاولة بطيئة (المحاولات 11-60):

  • كل ساعة واحدة
  • حتى 60 محاولة إجمالية (2.5 يوم)

الاستسلام بعد: 60 محاولة فاشلة

يجب أن تقوم نقطة النهاية الخاصة بك بـ:

  • الاستجابة خلال 5 ثوانٍ
  • إرجاع رمز حالة 200-299
  • المعالجة بشكل غير متزامن (لا تحجب الاستجابة)

الأمان

التحقق من توقيع Webhook (HMAC-SHA256):

العنوان: X-TenancyDesk-Signature

حساب التوقيع المتوقع:

import hmac
import hashlib

def verify_webhook(payload, signature, secret):
    expected = hmac.new(
        secret.encode('utf-8'),
        payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

# الاستخدام
if not verify_webhook(request.body, request.headers['X-TenancyDesk-Signature'], webhook_secret):
    return 'غير مصرح', 401

أفضل ممارسات الأمان:

  • تحقق دائماً من التوقيعات
  • استخدم HTTPS فقط (webhooks مرفوضة إذا HTTP)
  • نفذ idempotency (نفس الحدث قد يُسلم مرتين)
  • سجل جميع محاولات webhook للتصحيح

أنماط التكامل الشائعة

النمط 1: مزامنة الصفقات مع CRM

حالة الاستخدام: كل صفقة TenancyDesk تُنشئ تلقائياً في Zoho CRM

التنفيذ:

  1. اشترك في webhook deal.created
  2. عند الاستلام، استدعِ Zoho CRM API:
    # معالج webhook TenancyDesk
    if event['type'] == 'deal.created':
        deal = event['data']
        zoho.create_lead({
            'name': deal['tenant_name'],
            'value': deal['annual_rent'],
            'source': 'TenancyDesk'
        })
    

النمط 2: أتمتة المحاسبة

حالة الاستخدام: الدفع المستلم → إنشاء فاتورة في QuickBooks

التنفيذ:

  1. اشترك في payment.received
  2. استدعِ QuickBooks API لإنشاء فاتورة
  3. حدّث الصفقة بمعرف فاتورة QB

النمط 3: لوحة تحكم مخصصة

حالة الاستخدام: لوحة تحليلات في الوقت الفعلي

التنفيذ:

  1. استطلاع نقطة /deals كل 5 دقائق
  2. تجميع البيانات (صفقات حسب المرحلة، الإيرادات)
  3. عرض في لوحة تحكم مخصصة

معالجة الأخطاء

رموز حالة HTTP:

  • 200 OK - نجاح
  • 201 Created - تم إنشاء المورد
  • 400 Bad Request - معلمات غير صالحة
  • 401 Unauthorized - مفتاح API غير صالح/مفقود
  • 403 Forbidden - أذونات غير كافية
  • 404 Not Found - المورد غير موجود
  • 422 Unprocessable Entity - فشل التحقق
  • 429 Too Many Requests - تم تجاوز حد المعدل
  • 500 Internal Server Error - مشكلة في الخادم (أعد المحاولة)

تنسيق استجابة الخطأ:

{
  "error": {
    "code": "validation_failed",
    "message": "يجب أن يكون الإيجار السنوي أكبر من 0",
    "field": "annual_rent",
    "docs_url": "https://docs.tenancydesk.com/api/errors#validation"
  }
}

معالجة الأخطاء:

response = requests.post(url, headers=headers, json=data)

if response.status_code == 422:
    error = response.json()['error']
    print(f"فشل التحقق في {error['field']}: {error['message']}")
elif response.status_code == 429:
    retry_after = int(response.headers['Retry-After'])
    time.sleep(retry_after)
    # أعد الطلب
elif response.status_code >= 500:
    # exponential backoff للإعادة
    pass

أفضل الممارسات

تكاملات جاهزة للإنتاج:

  1. معالجة الأخطاء: التقط جميع أخطاء HTTP، نفذ منطق إعادة المحاولة
  2. Idempotency: استخدم عنوان Idempotency-Key لطلبات POST
  3. حد المعدل: احترم حدود المعدل، نفذ backoff
  4. أمان Webhook: تحقق دائماً من توقيعات HMAC
  5. التسجيل: سجل جميع استدعاءات API للتصحيح
  6. المراقبة: تتبع زمن وصول API ومعدلات الأخطاء
  7. الإصدار: استخدم عنوان إصدار API إذا كنت تثبت إصداراً معيناً

مثال طلب جاهز للإنتاج:

import requests
import time

def create_deal_with_retry(deal_data, max_retries=3):
    headers = {
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json',
        'Idempotency-Key': f'deal_{uuid4()}',
        'X-API-Version': '2025-12-01'
    }

    for attempt in range(max_retries):
        try:
            response = requests.post(
                'https://api.tenancydesk.com/v1/deals',
                headers=headers,
                json=deal_data,
                timeout=10
            )

            if response.status_code == 201:
                return response.json()['data']
            elif response.status_code == 429:
                wait = int(response.headers.get('Retry-After', 60))
                time.sleep(wait)
                continue
            elif response.status_code >= 500:
                time.sleep(2 ** attempt)  # Exponential backoff
                continue
            else:
                response.raise_for_status()

        except requests.exceptions.Timeout:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)

    raise Exception("تم تجاوز الحد الأقصى لإعادة المحاولات")

قم ببناء تكاملات قوية تتوسع مع عملك. تم تصميم TenancyDesk API لعمليات تكامل بمستوى الإنتاج على بنية تحتية سحابية راسخة.

هل كانت هذه المقالة مفيدة؟

مقالات ذات صلة

ابقَ على اطلاع

احصل على أحدث الأدلة والنصائح والتحديثات على بريدك الإلكتروني.

بالاشتراك، توافق على تلقي رسائل من TenancyDesk. يمكنك إلغاء الاشتراك في أي وقت.

هل تحتاج المزيد من المساعدة؟

فريق الدعم لدينا جاهز لمساعدتك في أي أسئلة.

اتصل بنا