Kommo + Fibery: Connect CRM to a Flexible Workspace Without Zapier

Fibery is a flexible workspace: databases, Kanban boards, roadmaps, documents - all in one place with a customizable data schema. Unlike Notion (documents with databases) or Linear (rigid structure), Fibery lets you build arbitrary relations between entities. For B2B SaaS and product companies that use Fibery for development management and Kommo for sales, the integration enables: creating a Fibery entity when a deal is closed, passing client data and deal amount, and linking to the relevant project or product.

Fibery API uses a Bearer token (Personal Access Token). The API is REST + GraphQL. REST operations: POST /api/commands with the fibery.entity/create command to create a new entity. The app schema defines the available types and fields.

Fibery App is a set of related data types (Client, Project, Task…). Each Fibery type has a unique namespace name (appName/typeName). Before writing the integration, you need to look up the exact type names from your workspace schema.

Retrieving the Fibery Schema

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()

Implementation: Creating a Fibery Entity on 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

Updating an Existing Entity

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},
            },
        }],
    )

To support updates, store the fibery_entity_id in a custom Kommo field (same approach as with other integrations). When the deal is updated again - check the field and update the existing entity rather than creating a new one.

Fibery Relations: Linking a Client to a 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}],
            },
        }],
    )

Link the created Client to an existing Project (for example, a product in your Fibery workspace):

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

Retrieving Fibery Data into 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 {}

Who This Is For

Product companies and agencies that use Fibery as their primary workspace for development and client management. Especially useful when Fibery stores information about your product, features, and client requests - and every new client from Kommo should automatically appear in that context.

A similar integration for software project managers: Kommo + Shortcut.

Frequently Asked Questions

How do I get a Personal Access Token in Fibery?

Go to Fibery Settings -> API -> Personal Access Tokens -> Create Token. The token does not expire automatically. Each integration should use a separate token. For team integrations, it is better to create a dedicated bot user in Fibery.

How do I handle Fibery Rich Text fields (documents)?

Fibery Rich Text is stored in Prosemirror JSON format. To write text via the API, pass Markdown (some fields support Markdown import) or use the Fibery Document format: {"type": "doc", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "..."}]}]}.

Does Fibery support webhooks for notifying external systems?

As of 2026, Fibery provides webhooks in experimental mode. A more reliable approach is polling via the Fibery API on a schedule (every 5 minutes): query entities where updatedAt > lastCheck. For production integrations this is preferable until the webhook API stabilizes.

Summary

Kommo + Fibery - a flexible workspace connected to your CRM without Zapier:

  • Bearer Token, POST /api/commands with fibery.entity/create
  • Generate the UUID locally and pass it in fibery/id
  • Retrieve type names via fibery.schema/query once before building the integration
  • Relations: fibery.entity/add-collection-items to link Client -> Project
  • A custom Kommo field stores the Fibery entity ID for subsequent updates

If you need an integration between Kommo and Fibery or another workspace tool - describe the task to the Exceltic.dev team.

More articles

All →