Developing a Custom REST Application for Bitrix24 Marketplace
A REST application for the Bitrix24 marketplace is not a local application installed on a specific portal, but a multi-user product that can be installed on any portal from the marketplace catalog. This changes the architecture requirements: the application must be multi-tenant from day one, handle independent data streams from thousands of portals, and not crash with unusual behavior from any of them.
How REST Application Differs from Local
Local application is created in a specific portal's settings via "Applications" → "For Developers". It works only on that portal, tokens are tightly bound, multi-tenancy is not needed.
REST application for marketplace is registered via partner.bitrix24.ru, has single client_id and client_secret for all installations. Each portal that installs your application gets its own access_token / refresh_token. Your service must store tokens from all portals and work with each independently.
The key installation identifier is member_id (hash, unique for each portal). All data in your database is partitioned by member_id.
Application Infrastructure
Minimal production infrastructure for a marketplace application:
Components:
-
OAuth server — handles
install,uninstall,loginhandlers - API service — takes requests from iframe, works with Bitrix24 REST API
- Worker/queue — processes webhooks from portals asynchronously
-
Database — stores tokens, settings, application data partitioned by
member_id -
Cache (Redis) — cache
access_tokenuntil TTL expires (3600 sec), infrequently changing data
Handlers that must be implemented:
POST /bitrix/install → receive code, exchange for tokens, save to database
POST /bitrix/uninstall → invalidate tokens, clean up portal data (GDPR)
POST /bitrix/login → SSO via Bitrix24 (optional, but convenient)
POST /bitrix/events → receive webhook events from portal
GET /bitrix/app → main iframe application page
OAuth Flow: Implementation Details
When the application is installed, Bitrix24 sends POST to the handler URL (registered when registering the application):
POST /bitrix/install
Content-Type: application/x-www-form-urlencoded
event=ONAPPINSTALL&auth[access_token]=...&auth[refresh_token]=...
&auth[member_id]=abc123&auth[domain]=company.bitrix24.ru
Here tokens already come in the installation body — no code exchange needed. Save everything to database. Token table schema:
CREATE TABLE app_installations (
id SERIAL PRIMARY KEY,
member_id VARCHAR(64) UNIQUE NOT NULL,
domain VARCHAR(255) NOT NULL,
access_token TEXT NOT NULL,
refresh_token TEXT NOT NULL,
expires_at TIMESTAMP NOT NULL,
scope TEXT,
installed_at TIMESTAMP DEFAULT NOW(),
uninstalled_at TIMESTAMP
);
CREATE INDEX ON app_installations (member_id);
Token refresh: when expires_at arrives (or getting 401 from portal API), make a request to https://oauth.bitrix.info/oauth/token/ with grant_type=refresh_token. Important: refresh must be atomic (mutex by member_id), otherwise parallel requests from multiple workers might simultaneously refresh the token and one gets stale.
Working with Bitrix24 REST API from Your Service
After obtaining access_token all requests to a specific portal go to its domain:
POST https://{domain}/rest/{method}
Authorization: Bearer {access_token}
Content-Type: application/json
Or token is passed in the body: auth={access_token}.
Rate limiting. Bitrix24 limits applications: no more than 2 requests/second per portal (some sources say up to 5 RPS on cloud plans). If exceeded — response {"error":"QUERY_LIMIT_EXCEEDED"}. You need a queue with rate limiter per member_id.
Batch requests. The batch method lets you combine up to 50 methods in one HTTP request. Critical for performance — instead of 50 separate HTTP round-trips, we do one.
Pagination. All list methods return maximum 50 items. Response has next (offset for next request) and total. To get all records you need a loop. For large data volumes (thousands of records) — definitely use asynchronous page processing.
Working with Placements: Embedding in Interface
Registration of placement on install:
// Call when processing ONAPPINSTALL
BX24.callMethod('placement.bind', {
PLACEMENT: 'CRM_DEAL_DETAIL_TAB',
HANDLER: 'https://your-app.com/bitrix/app?placement=crm_deal',
TITLE: 'Tab Name',
DESCRIPTION: 'Tab Description'
});
In iframe your application receives context via JS SDK:
BX24.init(function() {
BX24.placement.getInterface(function(data) {
// data.ID — deal/lead/contact ID
// data.ENTITY_TYPE — entity type
fetchDataForEntity(data.ID, data.ENTITY_TYPE);
});
// Resize iframe to content
BX24.fitWindow();
});
Cookies in iframe are inaccessible in Safari due to ITP. Session must be stored in localStorage or received via BX24.getAuth() on each open.
Handling Events (Webhooks)
Subscribe to events via event.bind on install:
POST /rest/event.bind
{
"event": "ONCRMDEALUPDATE",
"handler": "https://your-app.com/bitrix/events",
"auth_type": 0
}
Critical requirement: handler must respond with HTTP 200 within 5 seconds. All heavy processing — in a queue. Handler scheme:
POST /bitrix/events → verify signature → put in queue → respond 200
Worker → take from queue → process → update data
Security
Verification of incoming requests from Bitrix24: headers or body contains auth[application_token] — this is the static token of your application from settings in partner.bitrix24.ru. Check it on every incoming request.
For webhooks from event.bind the body contains auth[application_token] — same thing.
Development Timeline
| Volume | Timeline |
|---|---|
| Basic iframe application, CRM data reading | 3–5 weeks |
| Application with bidirectional sync and webhooks | 7–11 weeks |
| Multi-feature application with multiple placements and custom UI | 12–18 weeks |
| Ready for publication (testing, card design, moderation) | +3–5 weeks to any option |

