Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Add Docs
Bitrix24 REST API PHP SDK
https://github.com/bitrix24/b24phpsdk
Admin
An official PHP library for the Bitrix24 REST API that provides modern, type-safe access to Bitrix24
...
Tokens:
40,316
Snippets:
376
Trust Score:
7.2
Update:
1 day ago
Context
Skills
Chat
Benchmark
68.1
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Bitrix24 REST API PHP SDK (`bitrix24/b24phpsdk`) The Bitrix24 REST API PHP SDK is the official PHP library for interacting with the Bitrix24 REST API. It provides a strongly-typed, layered abstraction over the Bitrix24 REST endpoints, supporting both inbound webhooks (for single-portal integrations) and OAuth-based local applications (for mass-market Bitrix24 marketplace apps). The library ships two major coexisting versions: **v1** (`main` branch, PHP 8.2–8.4, stable/production) and **v3** (`v3` branch, PHP 8.4+, active development with access to new REST API v3 methods). Both versions follow PSR-4 autoloading under the `Bitrix24\SDK` namespace. The SDK is structured into layered components: `Core` (HTTP transport, credentials, exceptions), `Application` (OAuth lifecycle, local app management), `Infrastructure` (Symfony Console commands), and `Services` (one namespace per Bitrix24 API scope — CRM, Tasks, Users, Sale, Disk, Telephony, Calendar, IMOpenLines, etc.). All API responses are wrapped in typed result objects using `@property-read` PHPDoc annotations for IDE autocompletion. Batch operations use PHP Generators to process large datasets with constant low memory consumption. The v3 branch adds REST API v3 support (`/rest/api/` endpoint prefix), type-safe filter builders (`AbstractFilterBuilder`, `TaskFilter`), type-safe select builders (`TaskItemSelectBuilder`), and type-safe item builders (`TaskItemBuilder`). --- ## Installation Install the v1 stable version or the v3 active-development version via Composer. ```bash # Stable v1 (PHP 8.2+) composer require bitrix24/b24phpsdk:"^1.0" # v3 with API v3 support (PHP 8.4+) composer require bitrix24/b24phpsdk:"^3.1" ``` --- ## `ServiceBuilderFactory::createServiceBuilderFromWebhook` — Create a service builder from a webhook URL Instantiates the top-level `ServiceBuilder` pre-configured with webhook authentication. This is the fastest way to start calling the Bitrix24 REST API from a script or CLI tool. No OAuth dance is required — just paste your inbound webhook URL. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; require_once 'vendor/autoload.php'; $webhookUrl = 'https://your-portal.bitrix24.com/rest/1/your-webhook-token/'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook($webhookUrl); try { // Get application info $appInfo = $b24->getMainScope()->main()->getApplicationInfo()->applicationInfo(); echo 'App: ' . $appInfo->NAME . PHP_EOL; // Get current user profile $profile = $b24->getMainScope()->main()->getCurrentUserProfile()->getUserProfile(); echo 'User: ' . $profile->NAME . ' ' . $profile->LAST_NAME . PHP_EOL; // Call any unsupported method directly via core $response = $b24->core->call('user.current'); var_dump($response->getResponseData()->getResult()); } catch (BaseException | TransportException $e) { echo 'Error: ' . $e->getMessage() . PHP_EOL; } ``` --- ## `ServiceBuilderFactory::createServiceBuilderFromPlacementRequest` — Create service builder from a placement (OAuth) request Instantiates the `ServiceBuilder` from an incoming Symfony `Request` object sent by Bitrix24 when opening a local application. The `ApplicationProfile` holds the app's client ID, secret, and scopes. Used in web handlers that receive placement frames. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Services\ServiceBuilderFactory; use Symfony\Component\HttpFoundation\Request; require_once 'vendor/autoload.php'; $appProfile = ApplicationProfile::initFromArray([ 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'local.xxxxxxxx.yyyyyyyy', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'crm,task,user', ]); $request = Request::createFromGlobals(); $b24 = ServiceBuilderFactory::createServiceBuilderFromPlacementRequest($request, $appProfile); // Validate that the incoming auth token is genuine (security check) $b24->getMainScope()->main()->guardValidateCurrentAuthToken(); $profile = $b24->getMainScope()->main()->getCurrentUserProfile()->getUserProfile(); echo 'Logged-in user: ' . $profile->NAME . PHP_EOL; echo 'Is admin: ' . ($b24->getMainScope()->main()->isCurrentUserHasAdminRights()->isAdmin() ? 'yes' : 'no') . PHP_EOL; ``` --- ## `ServiceBuilder` scope accessors — Navigate to any API scope `ServiceBuilder` is the single entry point. Call the appropriate `get*Scope()` method to obtain a scope-level builder, then chain to the specific service. ```php <?php // All available scope accessors on ServiceBuilder: $b24->getMainScope() // Main: profile, server.time, app.info, scope, eventLog, events $b24->getCRMScope() // CRM: deal, contact, company, lead, quote, activity, item, ... $b24->getTaskScope() // Tasks (v3 API): task, checklistitem, commentitem, flow, stage, ... $b24->getUserScope() // User: current, get, add, update, search, countByFilter $b24->getDiskScope() // Disk: storage, folder, file $b24->getSaleScope() // Sale: order, payment, shipment, cashbox, paysystem, basket, ... $b24->getCalendarScope() // Calendar: calendar, event, resource $b24->getTelephonyScope() // Telephony: externalCall, externalLine, voximplant $b24->getIMScope() // IM: chat, message, notify, dialog $b24->getIMOpenLinesScope() // IMOpenLines: connector, config, session, bot, operator, message $b24->getLandingScope() // Landing: site, page, block, template, repo, demos $b24->getListsScope() // Lists: lists, field, section, element $b24->getBizProcScope() // Workflows: robot, activity, task $b24->getDepartmentScope() // Department: get, add, update, delete $b24->getEntityScope() // Entity: entity, item, section, property $b24->getAiAdminScope() // AI: engine register/list/unregister $b24->getCatalogScope() // Catalog: catalog, product, section, ... $b24->getPaysystemScope() // Paysystem: handler, paysystem, settings $b24->getPlacementScope() // Placement: bind, unbind, list $b24->getLogScope() // Log: blogPost.add $b24->getSonetGroupScope() // SonetGroup: create, update, delete, get, list, addUser $b24->getRestScope() // Rest: scope.list $b24->getUserConsentScope() // UserConsent $b24->getLegacyServiceBuilder() // Legacy Task v1 API (deprecated) ``` --- ## `CRMServiceBuilder::deal()` — CRM Deals CRUD Full create/read/update/delete operations for Bitrix24 CRM deals via the `crm.deal.*` REST methods. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; use Bitrix24\SDK\Core\Exceptions\BaseException; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $dealService = $b24->getCRMScope()->deal(); // Add a new deal $newDealId = $dealService->add([ 'TITLE' => 'New Contract', 'STAGE_ID' => 'NEW', 'CURRENCY_ID' => 'USD', 'OPPORTUNITY' => '15000', 'COMPANY_ID' => 42, 'CONTACT_ID' => 17, 'CLOSEDATE' => '2025-12-31T00:00:00+00:00', ])->getId(); echo 'Created deal ID: ' . $newDealId . PHP_EOL; // Get deal by ID $deal = $dealService->get($newDealId)->deal(); echo 'Title: ' . $deal->TITLE . PHP_EOL; echo 'Stage: ' . $deal->STAGE_ID . PHP_EOL; echo 'Amount: ' . $deal->OPPORTUNITY . PHP_EOL; // List deals with filter $deals = $dealService->list( ['DATE_CREATE' => 'DESC'], ['STAGE_ID' => 'NEW', '>OPPORTUNITY' => '10000'], ['ID', 'TITLE', 'STAGE_ID', 'OPPORTUNITY', 'CURRENCY_ID'] ); foreach ($deals->getDeals() as $d) { echo $d->ID . ': ' . $d->TITLE . ' — ' . $d->OPPORTUNITY . ' ' . $d->CURRENCY_ID . PHP_EOL; } // Count deals $total = $dealService->countByFilter(['STAGE_ID' => 'NEW']); echo 'Total NEW deals: ' . $total . PHP_EOL; // Update a deal $dealService->update($newDealId, ['STAGE_ID' => 'EXECUTING', 'OPPORTUNITY' => '18000']); // Delete a deal $dealService->delete($newDealId); ``` --- ## `Deal::batch` — Batch deal operations via PHP Generator The `Batch` service wraps bulk read/write operations using PHP Generators for memory-efficient processing of thousands of records. Each generator yields typed result items one at a time. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $batch = $b24->getCRMScope()->deal()->batch; // Batch list — streams all deals matching filter, no memory spike foreach ($batch->list( ['ID' => 'ASC'], ['STAGE_ID' => 'WON'], ['ID', 'TITLE', 'OPPORTUNITY', 'CURRENCY_ID'], 500 // optional limit ) as $deal) { echo $deal->ID . ': ' . $deal->TITLE . PHP_EOL; } // Batch add — create multiple deals in parallel API calls $dealsToAdd = [ ['TITLE' => 'Deal Alpha', 'STAGE_ID' => 'NEW', 'OPPORTUNITY' => '5000', 'CURRENCY_ID' => 'USD'], ['TITLE' => 'Deal Beta', 'STAGE_ID' => 'NEW', 'OPPORTUNITY' => '8000', 'CURRENCY_ID' => 'EUR'], ['TITLE' => 'Deal Gamma', 'STAGE_ID' => 'NEW', 'OPPORTUNITY' => '3000', 'CURRENCY_ID' => 'USD'], ]; $createdIds = []; foreach ($batch->add($dealsToAdd) as $result) { $createdIds[] = $result->getId(); echo 'Created: ' . $result->getId() . PHP_EOL; } // Batch delete foreach ($batch->delete($createdIds) as $result) { echo 'Deleted: ' . ($result->isSuccess() ? 'ok' : 'fail') . PHP_EOL; } // Batch update — array keyed by entity id, each value has 'fields' and optional 'params' $updates = [ $createdIds[0] => ['fields' => ['STAGE_ID' => 'EXECUTING']], $createdIds[1] => ['fields' => ['OPPORTUNITY' => '9500']], ]; foreach ($batch->update($updates) as $result) { echo 'Updated: ' . ($result->isSuccess() ? 'ok' : 'fail') . PHP_EOL; } ``` --- ## `TaskServiceBuilder::task()` — Tasks CRUD (REST API v3) Task operations (`tasks.task.*`) use Bitrix24 REST API v3 (`/rest/api/` endpoint prefix). The service accepts typed `TaskItemBuilder` for write operations and `TaskItemSelectBuilder` for field projection. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; use Bitrix24\SDK\Services\Task\Service\TaskItemBuilder; use Bitrix24\SDK\Services\Task\Service\TaskItemSelectBuilder; use Carbon\Carbon; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $taskService = $b24->getTaskScope()->task(); // Create a task using the typed builder (v3 API) $builder = new TaskItemBuilder( title: 'Prepare quarterly report', creatorId: 1, responsibleId: 5 ); $builder ->description('Review Q3 numbers and prepare slides') ->deadline(Carbon::now()->addDays(7)) ->priority('2') // high ->needsControl(true) ->groupId(12); $taskResult = $taskService->add($builder); $taskId = $taskResult->task()->id; echo 'Created task ID: ' . $taskId . PHP_EOL; // Get a task with specific fields selected (type-safe select builder) $select = (new TaskItemSelectBuilder()) ->title() ->description() ->deadline() ->status() ->responsible() ->creator(); $task = $taskService->get($taskId, $select)->task(); echo 'Task: ' . $task->title . PHP_EOL; echo 'Status: ' . $task->status . PHP_EOL; // Update a task using the builder $updateBuilder = new TaskItemBuilder('Updated Title', 1, 5); $updateBuilder->description('Updated description')->priority('1'); $taskService->update($taskId, $updateBuilder); // Delete a task $taskService->delete($taskId); ``` --- ## `TaskItemSelectBuilder` — Type-safe field selection for v3 Tasks Generated from the OpenAPI schema snapshot, `TaskItemSelectBuilder` provides IDE-autocomplete for every selectable field, including nested objects like `creator`, `responsible`, `chat`, `flow`, `group`, and `elapsedTime`. ```php <?php use Bitrix24\SDK\Services\Task\Service\TaskItemSelectBuilder; // Select only scalar fields $scalarSelect = (new TaskItemSelectBuilder()) ->title() ->status() ->deadline() ->priority() ->creatorId() ->responsibleId() ->groupId() ->stageId(); // Select nested object fields (expands to dot-notation, e.g., 'creator.id', 'creator.name') $richSelect = (new TaskItemSelectBuilder()) ->title() ->creator() // expands to creator.email, creator.id, creator.name, ... ->responsible() // expands to responsible.email, responsible.id, ... ->chat() // expands to chat.id, chat.entityId, chat.entityType ->flow() // expands to flow.id, flow.name ->group() // expands to group.id, group.name, group.type, ... ->elapsedTime(); // expands to elapsedTime.id, elapsedTime.minutes, ... // Select ALL system fields at once (reflection-based convenience method) $allFields = (new TaskItemSelectBuilder())->allSystemFields(); echo implode(', ', $richSelect->buildSelect()) . PHP_EOL; // Output: id, title, creator.email, creator.externalAuthId, ..., responsible.email, ... ``` --- ## `AbstractFilterBuilder` / `TaskFilter` — Type-safe REST v3 filter builders REST API v3 uses structured filter arrays instead of key-prefix filters. The `AbstractFilterBuilder` base class supports AND conditions, OR logic groups, and raw fallback. Entity-specific subclasses (like `TaskFilter`, `EventLogFilter`) add typed field accessors. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Filters\AbstractFilterBuilder; use Bitrix24\SDK\Services\Main\Service\EventLogFilter; use Bitrix24\SDK\Services\Main\Service\EventLogSelectBuilder; use Bitrix24\SDK\Core\Contracts\SortOrder; use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); // Use EventLogFilter (typed subclass of AbstractFilterBuilder) $filter = new EventLogFilter(); $filter->addCondition('severity', '=', 'error'); // With OR logic: $filter->or(function (EventLogFilter $f) { $f->addCondition('userId', '=', 5); $f->addCondition('userId', '=', 10); }); // Raw fallback for edge cases $filter->setRaw([['auditTypeId', 'in', [1, 2, 3]]]); $select = new EventLogSelectBuilder(); $select->allSystemFields(); $results = $b24->getMainScope()->eventLog()->list( select: $select, filter: $filter, order: ['timestamp' => SortOrder::Descending], pagination: ['limit' => 50, 'offset' => 0] ); foreach ($results->getEventLogs() as $entry) { echo $entry->id . ' — ' . $entry->severity . ' — ' . $entry->remoteAddr . PHP_EOL; } ``` --- ## `UserServiceBuilder::user()` — User management Full user listing, search, invite, update operations via `user.*` REST methods. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $userService = $b24->getUserScope()->user(); // Get current user $me = $userService->current()->user(); echo 'Me: ' . $me->NAME . ' ' . $me->LAST_NAME . ' <' . $me->EMAIL . '>' . PHP_EOL; // Search users by name $found = $userService->search(['NAME' => 'John']); foreach ($found->getUsers() as $user) { echo $user->ID . ': ' . $user->NAME . ' ' . $user->LAST_NAME . PHP_EOL; } // Get users by filter with ordering $admins = $userService->get( order: ['ID' => 'ASC'], filter: ['IS_ADMIN' => 'Y'], isAdminMode: true ); foreach ($admins->getUsers() as $admin) { echo 'Admin: ' . $admin->ID . ' — ' . $admin->EMAIL . PHP_EOL; } // Count users matching a filter $totalActive = $userService->countByFilter(['ACTIVE' => 'Y']); echo 'Active users: ' . $totalActive . PHP_EOL; // Invite a new user $newUserId = $userService->add([ 'NAME' => 'Jane', 'LAST_NAME' => 'Doe', 'EMAIL' => 'jane.doe@example.com', 'EXTRANET' => 'N', ], 'Welcome to the team!')->getId(); echo 'New user ID: ' . $newUserId . PHP_EOL; // Update a user $userService->update($newUserId, ['WORK_POSITION' => 'Senior Developer']); ``` --- ## `MainServiceBuilder::eventLog()` — System event log (REST v3) Query the Bitrix24 portal audit/event log via `main.eventlog.*` REST v3 methods. Supports get-by-id, filtered list, and tail-based polling for new entries. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; use Bitrix24\SDK\Services\Main\Service\EventLogSelectBuilder; use Bitrix24\SDK\Services\Main\Service\EventLogTailCursor; use Bitrix24\SDK\Core\Contracts\SortOrder; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $log = $b24->getMainScope()->eventLog(); // Fetch a single entry by ID $entry = $log->get(1234, (new EventLogSelectBuilder())->allSystemFields())->eventLog(); echo 'Event: ' . $entry->severity . ' at ' . $entry->remoteAddr . PHP_EOL; // List entries with pagination $results = $log->list( select: (new EventLogSelectBuilder())->allSystemFields(), filter: [], order: ['id' => SortOrder::Descending], pagination: ['limit' => 25, 'offset' => 0] ); foreach ($results->getEventLogs() as $e) { echo $e->id . ': severity=' . $e->severity . PHP_EOL; } // Tail — poll for new entries since a cursor (used in sync/streaming scenarios) $cursor = new EventLogTailCursor( field: 'id', order: SortOrder::Ascending, value: 1000, limit: 50 ); $newEntries = $log->tail( select: (new EventLogSelectBuilder())->allSystemFields(), filter: [], eventLogTailCursor: $cursor ); foreach ($newEntries->getEventLogs() as $e) { echo 'New entry: ' . $e->id . PHP_EOL; } ``` --- ## `CRMServiceBuilder::contact()` / `company()` / `lead()` — CRM entities The CRM scope exposes typed services for every CRM entity. The pattern is identical across contacts, companies, leads, and quotes. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $crm = $b24->getCRMScope(); // --- Contacts --- $contactId = $crm->contact()->add([ 'NAME' => 'Alice', 'LAST_NAME' => 'Smith', 'EMAIL' => [['VALUE' => 'alice@example.com', 'VALUE_TYPE' => 'WORK']], 'PHONE' => [['VALUE' => '+14155550100', 'VALUE_TYPE' => 'WORK']], 'COMPANY_ID' => 7, ])->getId(); $contact = $crm->contact()->get($contactId)->contact(); echo 'Contact: ' . $contact->NAME . ' ' . $contact->LAST_NAME . PHP_EOL; // Batch list all contacts modified today foreach ($crm->contact()->batch->list( ['ID' => 'ASC'], ['>DATE_MODIFY' => date('Y-m-d') . 'T00:00:00'], ['ID', 'NAME', 'LAST_NAME', 'EMAIL'] ) as $c) { echo $c->ID . ': ' . $c->NAME . PHP_EOL; } // --- Companies --- $companyId = $crm->company()->add([ 'TITLE' => 'Acme Corporation', 'COMPANY_TYPE' => 'CUSTOMER', 'INDUSTRY' => 'IT', 'CURRENCY_ID' => 'USD', ])->getId(); // --- Leads --- $leadId = $crm->lead()->add([ 'TITLE' => 'Inbound inquiry', 'NAME' => 'Bob', 'LAST_NAME' => 'Jones', 'STATUS_ID' => 'NEW', 'SOURCE_ID' => 'WEB', ])->getId(); $crm->lead()->update($leadId, ['STATUS_ID' => 'IN_PROCESS']); // Count contacts $total = $crm->contact()->countByFilter(['COMPANY_ID' => $companyId]); echo 'Contacts at Acme: ' . $total . PHP_EOL; ``` --- ## Error handling — typed exceptions All service methods declare `@throws BaseException | TransportException`. API v3 field-level validation errors throw `ValidationException` with structured `ValidationError[]` items. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Exceptions\ValidationException; use Bitrix24\SDK\Core\Exceptions\InvalidGrantException; use Bitrix24\SDK\Core\Exceptions\PortalUnavailableException; use Bitrix24\SDK\Core\Exceptions\ItemNotFoundException; use Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException; use Bitrix24\SDK\Core\Exceptions\PaymentRequiredException; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); try { $task = $b24->getTaskScope()->task()->get(999999)->task(); } catch (ValidationException $e) { // REST v3: field-level validation errors foreach ($e->getValidationErrors() as $error) { echo 'Field "' . $error->field . '": ' . $error->message . PHP_EOL; } } catch (ItemNotFoundException $e) { echo 'Entity not found: ' . $e->getMessage() . PHP_EOL; } catch (InvalidGrantException $e) { // OAuth refresh token expired — require user re-authorization echo 'OAuth token expired, redirect user to auth: ' . $e->getMessage() . PHP_EOL; } catch (PortalUnavailableException $e) { // Portal is on license suspension / redirect loop echo 'Portal unavailable: ' . $e->getMessage() . PHP_EOL; } catch (QueryLimitExceededException $e) { // Rate limit hit — implement back-off retry echo 'Rate limit: ' . $e->getMessage() . PHP_EOL; } catch (PaymentRequiredException $e) { echo 'Subscription expired: ' . $e->getMessage() . PHP_EOL; } catch (TransportException $e) { // Network / HTTP-level error echo 'Transport error: ' . $e->getMessage() . PHP_EOL; } catch (BaseException $e) { // Catch-all for all SDK exceptions echo 'SDK error: ' . $e->getMessage() . PHP_EOL; } ``` --- ## `LocalAppAuth` and file-based token storage — Local application auth `LocalAppAuth` holds the OAuth auth token, portal domain URL, application token, and OAuth server URL for a locally-installed Bitrix24 application. Combine with `AppAuthFileStorage` to persist tokens between requests. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Application\Local\Entity\LocalAppAuth; use Bitrix24\SDK\Application\Local\Infrastructure\Filesystem\AppAuthFileStorage; use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Services\ServiceBuilderFactory; use Symfony\Component\HttpFoundation\Request; require_once 'vendor/autoload.php'; $storagePath = __DIR__ . '/auth.json'; $storage = new AppAuthFileStorage($storagePath); // On install callback: save initial auth if (!file_exists($storagePath)) { $request = Request::createFromGlobals(); $appProfile = ApplicationProfile::initFromArray([ 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'local.xxx.yyy', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'secret', 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'crm', ]); $b24 = ServiceBuilderFactory::createServiceBuilderFromPlacementRequest($request, $appProfile); // Persist auth so subsequent requests can load it $storage->save(LocalAppAuth::initFromArray([ 'auth_token' => [ 'access_token' => $request->get('AUTH_ID'), 'refresh_token' => $request->get('REFRESH_ID'), 'expires' => (int)$request->get('AUTH_EXPIRES'), ], 'domain_url' => 'https://' . $request->get('DOMAIN'), 'application_token' => $request->get('APP_SID'), 'oauth_server_url' => 'https://oauth.bitrix.info', ])); } // On subsequent requests: load stored auth $localAuth = $storage->load(); $authToken = $localAuth->getAuthToken(); echo 'Access token: ' . $authToken->accessToken . PHP_EOL; echo 'Portal: ' . $localAuth->getDomainUrl() . PHP_EOL; ``` --- ## `SaleServiceBuilder` — E-commerce (Order, Payment, Shipment, Cashbox) The Sale scope covers the full Bitrix24 e-commerce stack: orders, payments, shipments, basket items, property groups, cashbox handlers, and more. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $sale = $b24->getSaleScope(); // Create an order $orderId = $sale->order()->add([ 'SITE_ID' => 's1', 'PERSON_TYPE_ID' => 1, 'CURRENCY' => 'USD', 'STATUS_ID' => 'N', 'RESPONSIBLE_ID' => 1, ])->getId(); echo 'Order ID: ' . $orderId . PHP_EOL; // Add basket item $sale->basketItem()->add([ 'ORDER_ID' => $orderId, 'NAME' => 'Widget Pro', 'PRICE' => '99.00', 'CURRENCY_ID' => 'USD', 'QUANTITY' => 2, 'MODULE' => 'catalog', ]); // Add payment $paymentId = $sale->payment()->add([ 'ORDER_ID' => $orderId, 'SUM' => '198.00', 'CURRENCY' => 'USD', 'PAY_SYSTEM_ID' => 1, ])->getId(); // Add shipment $shipmentId = $sale->shipment()->add([ 'ORDER_ID' => $orderId, 'DELIVERY_ID' => 1, 'PRICE' => '5.00', 'CURRENCY' => 'USD', ])->getId(); // List orders $orders = $sale->order()->list( filter: ['STATUS_ID' => 'N'], select: ['ID', 'ACCOUNT_NUMBER', 'PRICE', 'STATUS_ID'] ); foreach ($orders->getOrders() as $order) { echo $order->ID . ': ' . $order->PRICE . PHP_EOL; } ``` --- ## `CalendarServiceBuilder` — Calendar events and resources Manage calendar sections, events, and meeting resources. Supports batch add/update/delete for events. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $calendar = $b24->getCalendarScope(); // Create a calendar section $sectionId = $calendar->calendar()->add([ 'TYPE' => 'user', 'OWNER_ID' => 1, 'NAME' => 'My Work Calendar', 'COLOR' => '#3d85c8', 'DESCRIPTION' => 'Work schedule', ])->getId(); // Add an event $eventId = $calendar->event()->add([ 'TYPE' => 'user', 'OWNER_ID' => 1, 'FROM' => '2025-09-01T10:00:00', 'TO' => '2025-09-01T11:00:00', 'SECTION' => $sectionId, 'NAME' => 'Team stand-up', 'DESCRIPTION' => 'Daily sync', 'TZ_FROM' => 'Europe/Berlin', 'TZ_TO' => 'Europe/Berlin', ])->getId(); // Get upcoming events $upcoming = $calendar->event()->getNearest([ 'TYPE' => 'user', 'OWNER_ID' => 1, 'DAYS' => 7, 'CNT' => 10, ]); foreach ($upcoming->getEvents() as $event) { echo $event->NAME . ' — ' . $event->DATE_FROM . PHP_EOL; } // Delete event and section $calendar->event()->delete($eventId); $calendar->calendar()->delete($sectionId); ``` --- ## `IMOpenLinesServiceBuilder` — Open Lines (live chat connectors) Register external connectors, manage open line configurations, send and receive messages, and control sessions. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); $lines = $b24->getIMOpenLinesScope(); // Register a connector $lines->connector()->register([ 'ID' => 'my_connector', 'NAME' => 'My Chat Connector', ]); // List open line configurations $configs = $lines->config()->getList(['ACTIVE' => 'Y']); // Send a message through a connector $lines->connector()->sendMessages([ 'CONNECTOR' => 'my_connector', 'LINE' => 1, 'MESSAGES' => [ [ 'USER' => ['ID' => 'ext_user_42', 'NAME' => 'Alice External'], 'BODY' => 'Hello, I need help with my order #1234', 'FILES' => [], ], ], ]); // Operator actions $lines->operator()->answer(['CHAT_ID' => 101]); $lines->operator()->finish(['CHAT_ID' => 101]); // Bot automation $lines->bot()->sendMessage([ 'CHAT_ID' => 102, 'MESSAGE' => 'A human agent will be with you shortly.', ]); $lines->bot()->transferToOperator(['CHAT_ID' => 102]); ``` --- ## `core->call()` — Direct low-level API calls For any method not yet wrapped by a typed service, call it directly via `$b24->core->call()`. Returns a raw `Response` object. ```php <?php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; use Bitrix24\SDK\Core\Contracts\ApiVersion; require_once 'vendor/autoload.php'; $b24 = ServiceBuilderFactory::createServiceBuilderFromWebhook('https://your-portal.bitrix24.com/rest/1/token/'); // Call any REST v1 method $response = $b24->core->call('bizproc.robot.list'); $robots = $response->getResponseData()->getResult(); foreach ($robots as $robot) { echo $robot['CODE'] . ': ' . $robot['NAME'] . PHP_EOL; } // Call a REST v3 method $response = $b24->core->call( 'tasks.task.list', ['select' => ['id', 'title', 'status'], 'filter' => [['status', '=', '2']]], ApiVersion::v3 ); $tasks = $response->getResponseData()->getResult(); foreach ($tasks['tasks'] as $task) { echo $task['id'] . ': ' . $task['title'] . PHP_EOL; } // Inspect pagination $pagination = $response->getResponseData()->getPagination(); echo 'Total: ' . $pagination->getTotal() . PHP_EOL; echo 'Next offset: ' . $pagination->getNextItem() . PHP_EOL; ``` --- ## Application Contracts — Building Marketplace Applications The `Bitrix24\SDK\Application\Contracts` namespace provides four bounded contexts with abstract contract tests for building production-ready marketplace apps. ```php <?php // Contracts to implement for a full marketplace application: // // Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface // Methods: applicationInstalled, applicationUninstalled, updateAuthToken, isMasterAccount, ... // // Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface // Methods: applicationInstalled, applicationUninstalled, linkContactPerson, linkBitrix24Partner, ... // // Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface // Methods: changeEmail, changeMobilePhone, markEmailAsVerified, markMobilePhoneAsVerified, // getUserAgentInfo, isEmailVerified, isMobilePhoneVerified, isPartner // // Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface // Methods: getBitrix24PartnerNumber, getName, ... // Validate your implementations with the shipped contract tests: // tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php // tests/Unit/Application/Contracts/ApplicationInstallations/... // tests/Unit/Application/Contracts/ContactPersons/... // tests/Unit/Application/Contracts/Bitrix24Partners/... // Example: handling OnApplicationInstall event use Bitrix24\SDK\Application\RemoteEventsFactory; use Symfony\Component\HttpFoundation\Request; $factory = new RemoteEventsFactory(/* dependencies */); $request = Request::createFromGlobals(); $event = $factory->create($request); if ($event instanceof \Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\OnApplicationInstall) { $authToken = $event->getAuthToken(); $memberId = $event->getMemberId(); $applicationToken = $event->getApplicationToken(); // Persist Bitrix24Account and ApplicationInstallation to your database } ``` --- ## Summary The `bitrix24/b24phpsdk` library is suited for two primary integration patterns. First, **inbound webhook integrations**: any script or background job that needs to read from or write to a single Bitrix24 portal — e.g., syncing orders to an ERP, pushing CRM contacts from a form, or monitoring the event log. Start with `ServiceBuilderFactory::createServiceBuilderFromWebhook($url)`, navigate to the appropriate scope (`getCRMScope()->deal()`, `getTaskScope()->task()`, `getUserScope()->user()`, etc.), and call typed service methods. Use batch services for bulk reads or writes to keep memory consumption constant regardless of dataset size. Second, **OAuth marketplace applications**: apps distributed through the Bitrix24 marketplace that run on multiple customer portals simultaneously. Implement the four `Application\Contracts` interfaces (`Bitrix24AccountInterface`, `ApplicationInstallationInterface`, `ContactPersonInterface`, `Bitrix24PartnerInterface`) backed by your own database layer, then initialize the service builder from placement requests using `createServiceBuilderFromPlacementRequest`. The SDK handles automatic access token refresh, regional OAuth server URL discovery, and security signature validation (`guardValidateCurrentAuthToken`). The v3 branch additionally exposes Bitrix24 REST API v3 methods (Tasks, EventLog, and more to come) with structured filter builders, typed select builders, and a `ValidationException` hierarchy for REST v3 field-level error responses.