Kommo + Fibery: связка CRM и гибкого workspace без Zapier

Fibery - гибкий workspace: базы данных, Kanban, дорожные карты, документы - всё в одном, с настраиваемой схемой данных. В отличие от Notion (документы с базами) или Linear (жёсткая структура), Fibery позволяет строить произвольные связи между сущностями. Для B2B SaaS и продуктовых компаний, использующих Fibery для управления разработкой и Kommo для продаж, интеграция позволяет: создавать Fibery-сущность при закрытии сделки, передавать данные клиента и сумму, связывать с нужным проектом или продуктом.

Fibery API использует Bearer token (Personal Access Token). API - REST + GraphQL. REST-операции: POST /api/commands с fibery.entity/create командой для создания новой сущности. Схема приложения определяет доступные типы (Types) и поля.

Fibery App - набор связанных типов данных (Client, Project, Task…). Каждый Fibery тип имеет уникальное имя пространства (appName/typeName). Перед написанием интеграции нужно узнать точные имена типов из схемы своего workspace.

Получение схемы Fibery

import requests, os

FIBERY_TOKEN   = os.environ["FIBERY_TOKEN"]
FIBERY_ACCOUNT = os.environ["FIBERY_ACCOUNT"]  # yourworkspace.fibery.io
FIBERY_BASE    = f"https://{FIBERY_ACCOUNT}/api"
FIBERY_HDR     = {
    "Authorization": f"Token {FIBERY_TOKEN}",
    "Content-Type":  "application/json",
}

def get_schema():
    r = requests.post(
        f"{FIBERY_BASE}/commands",
        headers=FIBERY_HDR,
        json=[{"command": "fibery.schema/query"}],
    )
    for type_info in r.json()[0].get("result", {}).get("fibery/types", []):
        name = type_info.get("fibery/name", "")
        if not name.startswith("fibery/"):  # пропустить системные типы
            print(f"Type: {name}")
            for field in type_info.get("fibery/fields", []):
                print(f"  Field: {field.get('fibery/name')} ({field.get('fibery/type', {}).get('fibery/name', '')})")

# Запустить один раз для получения имён типов
get_schema()

Реализация: создание сущности в Fibery при Closed Won

from flask import Flask, request, jsonify
import uuid

app = Flask(__name__)

KOMMO_SUBDOMAIN = os.environ["KOMMO_SUBDOMAIN"]
KOMMO_TOKEN     = os.environ["KOMMO_ACCESS_TOKEN"]
CLOSED_WON_ID   = int(os.environ["KOMMO_CLOSED_WON_ID"])

# Имена типов из схемы вашего Fibery workspace
FIBERY_CLIENT_TYPE = os.environ.get("FIBERY_CLIENT_TYPE", "Sales/Client")

KOMMO_BASE = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4"
KOMMO_HDR  = {"Authorization": f"Bearer {KOMMO_TOKEN}", "Content-Type": "application/json"}

def get_lead_contact(lead_id: int) -> tuple[dict, dict]:
    r = requests.get(
        f"{KOMMO_BASE}/leads/{lead_id}",
        headers=KOMMO_HDR,
        params={"with": "contacts"},
    )
    lead     = r.json()
    contacts = lead.get("_embedded", {}).get("contacts", [])
    contact  = {}
    if contacts:
        rc = requests.get(
            f"{KOMMO_BASE}/contacts/{contacts[0]['id']}",
            headers=KOMMO_HDR,
            params={"with": "custom_fields_values"},
        )
        contact = rc.json()
    return lead, contact

def get_email(contact: dict) -> str:
    for cf in contact.get("custom_fields_values", []) or []:
        if cf.get("field_code") == "EMAIL":
            vals = cf.get("values", [])
            if vals:
                return vals[0].get("value", "")
    return ""

def create_fibery_entity(type_name: str, fields: dict) -> str:
    entity_id = str(uuid.uuid4())
    r = requests.post(
        f"{FIBERY_BASE}/commands",
        headers=FIBERY_HDR,
        json=[{
            "command": "fibery.entity/create",
            "args": {
                "type":   type_name,
                "entity": {"fibery/id": entity_id, **fields},
            },
        }],
    )
    r.raise_for_status()
    result = r.json()
    if isinstance(result, list) and result:
        return result[0].get("result", {}).get("fibery/id", entity_id)
    return entity_id

def add_note(lead_id: int, text: str):
    requests.post(
        f"{KOMMO_BASE}/notes",
        headers=KOMMO_HDR,
        json=[{
            "entity_id":   lead_id,
            "entity_type": "leads",
            "note_type":   "common",
            "params":      {"text": text},
        }],
    )

@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
    data = request.json or {}
    for lead_data in data.get("leads", {}).get("status", []):
        lead_id    = lead_data.get("id")
        new_status = lead_data.get("status_id")
        if new_status != CLOSED_WON_ID:
            continue

        lead, contact = get_lead_contact(lead_id)
        client_name   = contact.get("name", f"Lead #{lead_id}")
        deal_amount   = float(lead.get("price") or 0)
        email         = get_email(contact)

        # Поля зависят от схемы вашего Fibery workspace
        # Ниже - пример для типа "Sales/Client"
        fibery_fields = {
            "Sales/Name":         client_name,
            "Sales/Email":        email,
            "Sales/DealAmount":   deal_amount,
            "Sales/KommoLeadId":  str(lead_id),
            "Sales/DealName":     lead.get("name", ""),
        }

        entity_id = create_fibery_entity(FIBERY_CLIENT_TYPE, fibery_fields)
        add_note(
            lead_id,
            f"Fibery: создана сущность {FIBERY_CLIENT_TYPE} (ID: {entity_id}) для клиента {client_name}.",
        )

    return jsonify({"status": "ok"}), 200

Обновление существующей сущности

def update_fibery_entity(entity_id: str, type_name: str, fields: dict):
    requests.post(
        f"{FIBERY_BASE}/commands",
        headers=FIBERY_HDR,
        json=[{
            "command": "fibery.entity/update",
            "args": {
                "type":   type_name,
                "entity": {"fibery/id": entity_id, **fields},
            },
        }],
    )

Для обновления сохраните fibery_entity_id в кастомном поле Kommo (аналогично другим интеграциям). При повторных изменениях сделки - проверяйте поле и обновляйте сущность, а не создавайте новую.

Фибери Relations: связать Client с Project

def create_relation(entity_id: str, related_entity_id: str,
                    relation_field: str, entity_type: str):
    requests.post(
        f"{FIBERY_BASE}/commands",
        headers=FIBERY_HDR,
        json=[{
            "command": "fibery.entity/add-collection-items",
            "args": {
                "type":            entity_type,
                "field":           relation_field,
                "entity":          {"fibery/id": entity_id},
                "items":           [{"fibery/id": related_entity_id}],
            },
        }],
    )

Связать созданного Client с существующим Project (например, продукт в вашем Fibery):

project_id = os.environ.get("FIBERY_DEFAULT_PROJECT_ID", "")
if project_id:
    create_relation(entity_id, project_id, "Sales/Projects", FIBERY_CLIENT_TYPE)

Получение данных из Fibery в Kommo

def get_fibery_entity(entity_id: str, type_name: str, fields: list[str]) -> dict:
    r = requests.post(
        f"{FIBERY_BASE}/commands",
        headers=FIBERY_HDR,
        json=[{
            "command": "fibery.entity/query",
            "args": {
                "query": {
                    "q/from":   type_name,
                    "q/select": ["fibery/id"] + fields,
                    "q/where":  ["=", ["fibery/id"], "$id"],
                    "q/limit":  1,
                },
                "params": {"$id": entity_id},
            },
        }],
    )
    result = r.json()
    if isinstance(result, list) and result:
        items = result[0].get("result", [])
        return items[0] if items else {}
    return {}

Для кого актуально

Продуктовые компании и агентства, использующие Fibery как основной workspace для разработки и управления клиентами. Особенно полезно когда в Fibery хранится информация о продукте, фичах, клиентских запросах - и каждый новый клиент из Kommo должен автоматически появляться в этом контексте.

Аналогичная интеграция для software PM: Kommo + Shortcut.

Часто задаваемые вопросы

Как получить Personal Access Token в Fibery?

Fibery Settings -> API -> Personal Access Tokens -> Create Token. Токен не истекает автоматически. Каждая интеграция должна использовать отдельный токен. Для team-интеграций лучше создать отдельного bot-пользователя в Fibery.

Как обрабатывать Fibery Rich Text поля (документы)?

Fibery Rich Text хранится в формате Prosemirror JSON. Для записи текста через API передавайте Markdown (некоторые поля поддерживают Markdown-импорт) или используйте формат Fibery Document: {"type": "doc", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "..."}]}]}.

Поддерживает ли Fibery webhooks для уведомления внешних систем?

В 2026 году Fibery предоставляет webhooks в экспериментальном режиме. Более надёжный подход - polling через Fibery API по расписанию (каждые 5 минут): запрашивать сущности с updatedAt > lastCheck. Для production интеграций это предпочтительнее до стабилизации webhook API.

Итог

Kommo + Fibery - гибкий workspace из CRM без Zapier:

  • Bearer Token, POST /api/commands с fibery.entity/create
  • UUID генерировать локально и передавать в fibery/id
  • Имена типов получить через fibery.schema/query один раз перед интеграцией
  • Relations: fibery.entity/add-collection-items для связи Client -> Project
  • Кастомное поле Kommo хранит Fibery entity ID для последующих обновлений

Если нужна интеграция Kommo с Fibery или другим workspace-инструментом - опишите задачу команде Exceltic.dev.

Ещё статьи

Все →