Bitrix24 and Jira Integration
Managers assign tasks in Bitrix24, developers work in Jira. The result is predictable: manager asks about status in chat, developer switches to B24 to update the task, forgets, manager sees outdated information. Or the opposite — PM closes an issue in Jira, but the B24 task remains open for another week. Double data entry isn't just inconvenient — it's systematic loss of project control.
Synchronization Architecture
The integration works through bidirectional data exchange via REST APIs of both systems. Bitrix24 REST API provides and accepts task data, Jira REST API v3 — issue data. Between them stands middleware that processes events, transforms data, and manages conflicts.
B24 Task (event) → Webhook → Middleware → Jira REST API → Issue
Jira Issue (event) → Jira Webhook → Middleware → B24 REST API → Task
Middleware stores a mapping table: each "B24 task — Jira issue" pair is linked by ID. When one entity updates, middleware finds its pair and updates it. Without this table, sync is impossible — IDs in the systems differ, there's no direct connection.
Field Mapping
Fields in B24 and Jira don't match by name or format. We configure correspondence:
| B24 Field (tasks.task) | Jira Field (issue) | Note |
|---|---|---|
| TITLE | summary | Direct match |
| DESCRIPTION | description | B24 is HTML, Jira is ADF (Atlassian Document Format). Middleware converts |
| RESPONSIBLE_ID | assignee (accountId) | Via user mapping table |
| CREATED_BY | reporter | Same |
| DEADLINE | duedate | Date format: B24 is ISO 8601, Jira is YYYY-MM-DD |
| PRIORITY | priority.id | Value mapping: 1→Highest, 2→High, 3→Medium |
| STATUS | status.id | Separate correspondence table (see below) |
| GROUP_ID (project) | project.key | B24 project → Jira project |
| UF_* (custom fields) | customfield_* | Configured individually |
Description conversion is a separate task. B24 stores descriptions in HTML, Jira v3 uses Atlassian Document Format (JSON tree). Middleware parses HTML into DOM, transforms into ADF nodes (paragraph, text, heading, bulletList) and back.
Status Mapping
The most delicate part. Each Jira team has its own workflow, B24 has its own task stages and custom kanban statuses. Middleware uses a configurable table:
| B24 Status | Jira Status | Direction |
|---|---|---|
| New (2) | To Do | ↔ |
| In Progress (3) | In Progress | ↔ |
| Awaiting Review (4) | In Review | B24 → Jira |
| On Hold (6) | On Hold | ↔ |
| Completed (5) | Done | ↔ |
| — | QA Testing | Jira → B24 (custom field) |
Direction "↔" means: when status changes in either system, the paired entity updates. Direction "→" means sync only one way (usually for statuses that don't exist in the other system).
Transitioning status in Jira isn't just writing a value. Jira requires calling POST /rest/api/3/issue/{id}/transitions with the ID of a specific transition. Middleware first requests available transitions for an issue, finds the right one, and executes it.
Webhook Subscriptions
From B24:
Register handlers via event.bind:
-
ONTASKADD— new task → issue creation in Jira -
ONTASKUPDATE— field update → issue update -
ONTASKCOMMENTADD— new comment → issue comment -
ONTASKDELETE— task deletion → issue closure or deletion (configurable)
From Jira:
Webhook via Settings → Webhooks or Jira App:
-
jira:issue_created— new issue → task creation in B24 -
jira:issue_updated— field/status update → task update -
comment_created— comment → task comment in B24
Each webhook contains a payload with full data set. Middleware extracts changed fields from changelog.items (Jira) or compares with saved state (B24, where changelog isn't provided).
Loop Prevention
Critical issue: B24 updates task → middleware updates issue → Jira sends webhook → middleware updates B24 task → infinite loop.
Solution — marking the source of update. Middleware sets a flag in a custom field with every update:
- In B24:
UF_SYNC_SOURCE = "jira"when updated from Jira - In Jira:
customfield_sync_source = "b24"when updated from B24
When middleware receives a webhook, it checks this flag. If the update came from itself — it skips processing. The flag resets after 5 seconds (cron task).
Comment Synchronization
Comments sync in both directions with author attribution:
- From B24 to Jira:
POST /rest/api/3/issue/{id}/commentwith body{body: {type: "doc", content: [...]}}. Author name from B24 is added at the beginning. - From Jira to B24:
task.commentitem.addwith comment text. Author name from Jira — in the prefix.
Comment attachments: files are downloaded from one side, uploaded to the other. For Jira — POST /rest/api/3/issue/{id}/attachments, for B24 — task.commentitem.add with prior file upload to disk.
Initial Migration
Before enabling sync, existing data must be migrated. Middleware supports bulk operations:
- Export all tasks from selected B24 projects via
tasks.task.listwith pagination. - Create issues in Jira via bulk API (
POST /rest/api/3/issue/bulk). - Populate the ID mapping table.
- Re-export issues from Jira that don't exist in B24, create tasks.
Migration runs once. After that, real-time sync activates via webhooks.
Rights and Security
- Jira API requires OAuth 2.0 (for Cloud) or Personal Access Token (for Server/Data Center). Middleware stores tokens encrypted.
- B24 — OAuth 2.0 with scope
task,user. Refresh token updates automatically. - User mapping: B24 User ID ↔ Jira Account ID correspondence table. Populated by email or manually.
- Task data passes only through your middleware — neither system gets direct access to the other.
What We Deploy
- Middleware for bidirectional task/issue sync between B24 and Jira
- Configurable field, status, and priority mapping
- Comment and attachment synchronization
- Update loop protection
- Initial migration of existing tasks
- User mapping between systems
- Monitoring and logging of all sync operations







