leadora/agents-api

PHP client for the Leadora agent panel API

Maintainers

Package info

github.com/behzad-azizan/leadora-agents-api

pkg:composer/leadora/agents-api

Transparency log

Statistics

Installs: 11

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-08-11 18:38 UTC

This package is auto-updated.

Last update: 2026-08-11 18:57:31 UTC


README

کلاینت PHP برای API پنل نمایندگی لیدورا (/api/v1).

نصب

composer require leadora/agents-api

توسعه محلی:

{
    "repositories": [
        {
            "type": "path",
            "url": "/home/behzad/Documents/php-projects/leadora-agents-api"
        }
    ],
    "require": {
        "leadora/agents-api": "@dev"
    }
}

راه‌اندازی

use Leadora\Agents\LeadoraClient;

$client = LeadoraClient::create(
    baseUrl: env('LEADORA_BASE_URL'),   // مثلا https://api.leadora.example
    apiToken: env('LEADORA_API_TOKEN'), // توکن نماینده
);

همه درخواست‌ها با هدر Authorization: Bearer <token> احراز هویت می‌شوند. هر endpoint یک scope مشخص نیاز دارد که باید روی توکن فعال باشد.

فهرست endpointها

متد کلاینت HTTP Scope Idempotency-Key
profile()->get() GET /api/v1/agent/profile profile.read
users()->register() POST /api/v1/users users.write
leads()->preview() POST /api/v1/leads/preview preview.create
leads()->naturalLanguagePreview() POST /api/v1/leads/natural-language-preview preview.create
leads()->campaignMessagePreview() POST /api/v1/leads/campaign-message-preview preview.create
leads()->quote() POST /api/v1/leads/quote quote.create
orders()->create() POST /api/v1/orders orders.create الزامی
orders()->pay() POST /api/v1/orders/{id}/pay orders.pay الزامی
orders()->listLeads() GET /api/v1/orders/{id}/leads exports.read
orders()->listAllLeadMobiles() حلقه روی listLeads exports.read
orders()->createExport() POST /api/v1/orders/{id}/exports exports.create الزامی
exports()->get() GET /api/v1/exports/{id} exports.read
exports()->download() GET /api/v1/exports/{id}/download exports.read

۱. پروفایل نماینده و موجودی کیف پول

$profile = $client->profile()->get();

$profile->agent->id;              // agt_...
$profile->agent->status;          // active | suspended | disabled
$profile->wallet->balanceAmount;  // ریال (int)

۲. ثبت کاربر بعد از signup

ثبت کاربر upsert است؛ external_user_id تکراری برای همان نماینده، کاربر قبلی را به‌روزرسانی می‌کند.

use Leadora\Agents\Users\RegisterUserRequest;

$user = $client->users()->register(new RegisterUserRequest(
    externalUserId: (string) $localUser->id,
    mobile: $localUser->mobile,        // اختیاری
    email: $localUser->email,          // اختیاری
    fullName: $localUser->full_name,   // اختیاری
    metadata: ['plan' => 'gold'],      // اختیاری
));

$leadoraUserId = $user->id; // usr_...

۳. پیش‌نمایش تعداد لید

use Leadora\Agents\Filter\LeadFilter;
use Leadora\Agents\Leads\PreviewRequest;

$filter = new LeadFilter(
    provinceIds: [8],
    cityIds: [301],
    gender: 'male',            // male | female | unknown
    ageFrom: 25,
    ageTo: 40,
    mobileOperatorIds: [1],
    mobilePrefixes: [912],     // پیش‌شماره سه‌رقمی
);

$preview = $client->leads()->preview(new PreviewRequest(
    filter: $filter,
    userId: $leadoraUserId,                          // اختیاری
    countType: PreviewRequest::COUNT_TYPE_ESTIMATED, // exact | estimated
));

$preview->matchedCount;
$preview->countType;   // exact | estimated | placeholder
$preview->filterHash;

۳.۱ پیش‌نمایش با زبان طبیعی

use Leadora\Agents\Leads\NaturalLanguagePreviewRequest;

$nl = $client->leads()->naturalLanguagePreview(new NaturalLanguagePreviewRequest(
    naturalLanguageIntent: 'شماره مردان ۲۰ تا ۶۰ سال ساکن تهران و اصفهان که در حوزه لوازم آرایشی یا عروسی کار می‌کنند',
    userId: $leadoraUserId,
    countType: NaturalLanguagePreviewRequest::COUNT_TYPE_ESTIMATED,
));

$nl->resolvedFilter;     // فیلتر ساختاریافته نهایی
$nl->appliedFilters;     // توضیح فارسی فیلترها
$nl->matchedCount;
$nl->interpretationFa;

۳.۲ پیشنهاد مخاطب از روی متن پیام

use Leadora\Agents\Leads\CampaignMessagePreviewRequest;

$suggested = $client->leads()->campaignMessagePreview(new CampaignMessagePreviewRequest(
    campaignMessage: 'فروش ویژه لوازم آرایشی با ۳۰٪ تخفیف فقط تا آخر هفته',
    userId: $leadoraUserId,
));

$suggested->resolvedFilter;
$suggested->messageFa;
$suggested->matchedCount;

برای فعال‌سازی، ادمین باید در تنظیمات سیستم این کلیدها را ست کند:

  • openai_api_key
  • openai_model (پیش‌فرض: gpt-4o-mini)
  • openai_enabled (true / false)

۴. گرفتن پیش‌فاکتور (قیمت قفل‌شده)

use Leadora\Agents\Leads\QuoteRequest;

$quote = $client->leads()->quote(new QuoteRequest(
    userId: $leadoraUserId,   // الزامی — usr_...
    filter: $filter,
    requestedCount: 1000,
));

$quote->id;           // qt_...
$quote->unitPrice;    // ریال
$quote->totalAmount;  // ریال
$quote->expiresAt;    // RFC3339 — قیمت تا این زمان معتبر است
$quote->pricingBreakdown->baseUnitPrice;
$quote->pricingBreakdown->taxPercent;
$quote->pricingBreakdown->multipliers; // [key, value]

۵. ثبت و پرداخت سفارش

سه endpoint سفارش/خروجی هدر Idempotency-Key الزامی دارند. اگر کلید ندهید SDK خودش یک UUID می‌سازد؛ ولی برای retry امن بهتر است کلید را خودتان بسازید و ذخیره کنید تا در تکرار همان کلید ارسال شود.

$order = $client->orders()->create($quote->id, idempotencyKey: $myStoredKey);

$order->id;      // ord_...
$order->status;  // pending_payment

$paid = $client->orders()->pay($order->id, idempotencyKey: $myPayKey);

$paid->order->status;               // paid
$paid->order->paidAt;
$paid->wallet->balanceAmount;       // موجودی بعد از کسر

پرداخت سفارشِ قبلا پرداخت‌شده خطا نمی‌دهد و وضعیت فعلی را برمی‌گرداند.

۶. دریافت شماره به‌صورت batch (پیشنهادی برای حجم زیاد)

$batch = $client->orders()->listLeads($order->id, offset: 0, limit: 1000);

$batch->totalCount;
$batch->hasMore;
$batch->mobiles(); // ['0912...', ...]

// یا همه شماره‌ها را یک‌جا بگیرید (صفحات را خودش می‌چرخاند)
$mobiles = $client->orders()->listAllLeadMobiles($order->id, pageLimit: 1000);

در اولین فراخوانی شماره‌ها تخصیص و ذخیره می‌شوند؛ فراخوانی‌های بعدی همان لیست پایدار را برمی‌گردانند.

۷. خروجی فایل (Export — اختیاری برای حجم کم)

use Leadora\Agents\Exports\Export;

$export = $client->orders()->createExport($order->id, Export::FILE_TYPE_CSV);

// ساخت فایل async است؛ وضعیت را poll کنید
$export = $client->exports()->get($export->id);

if ($export->isReady()) {
    $download = $client->exports()->download($export->id);
    // فعلا metadata + message برمی‌گردد؛ لینک دانلود بعدا اضافه می‌شود
}

وضعیت‌های export: pending، generating، ready، failed، expired

خطاها

use Leadora\Agents\Exception\ApiException;

try {
    $client->orders()->pay($orderId);
} catch (ApiException $e) {
    $e->errorCode;   // مثلا ApiException::INSUFFICIENT_WALLET_BALANCE
    $e->statusCode;  // مثلا 409
    $e->getMessage();
}

کدهای خطای مهم (به‌صورت ثابت روی ApiException تعریف شده‌اند):

کد HTTP توضیح
VALIDATION_ERROR 400 ورودی نامعتبر / نبودن Idempotency-Key
UNAUTHORIZED / TOKEN_REVOKED / TOKEN_EXPIRED 401 مشکل توکن
AGENT_DISABLED / IP_NOT_ALLOWED / SCOPE_NOT_ALLOWED 403 دسترسی
USER_NOT_FOUND / QUOTE_NOT_FOUND / ORDER_NOT_FOUND / EXPORT_NOT_FOUND 404 یافت نشد
QUOTE_EXPIRED 409 پیش‌فاکتور منقضی شده
ORDER_NOT_PAYABLE 409 سفارش قابل پرداخت نیست
ORDER_NOT_READY_FOR_DELIVERY 409 سفارش هنوز برای تحویل لید آماده نیست
INSUFFICIENT_WALLET_BALANCE 409 موجودی کیف پول کافی نیست
EXPORT_NO_LEADS 409 لید منطبق برای تخصیص پیدا نشد
EXPORT_NOT_READY / EXPORT_EXPIRED 409 خروجی آماده/معتبر نیست
IDEMPOTENCY_CONFLICT 409 کلید تکراری با بدنه متفاوت
INTERNAL_ERROR 500 خطای داخلی سرور

فیلترهای مجاز

فقط این فیلدها در LeadFilter پشتیبانی می‌شوند:

province_ids, city_ids, municipal_district_nos, gender, age_from, age_to, birth_year_from, birth_year_to, mobile_operator_ids, mobile_prefixes, source_ids, batch_ids

فیلتر روی فیلدهای هویتی و بانکی (نام، کد ملی، شماره کارت و ...) توسط سرور رد می‌شود.

نکته درباره مبالغ

همه مبالغ ریال و از نوع int هستند. هرگز float استفاده نکنید.

تست

composer install
./vendor/bin/phpunit