Synchronization between Kommo and Airtable works through a direct connection: a Kommo webhook on deal status change -> your middleware -> Airtable REST API (POST/PATCH /v0/{baseId}/{tableIdOrName}/records). The reverse direction - Airtable Automation -> your endpoint -> Kommo API PATCH /api/v4/leads/{id}. There is no native two-way integration between these platforms; no-code bridges like Zapier or Albato do not provide the flexibility needed at 500+ deals per month.
The operations team maintains a project database in Airtable: deadlines, owners, onboarding statuses. Sales close deals in Kommo. At some point the data diverges: a manager moves a deal to “Won” - the operations person does not see it until someone manually updates the row in Airtable. Or the reverse: a client signed an act in Airtable - the salesperson finds out via messenger, not from the CRM.
In Exceltic.dev projects this scenario appears consistently at companies of 15+ people where sales and operations are tracked in different tools. This article describes the concrete architecture for two-way sync and the real API parameters you need to know before starting development.
Why there is no native integration
Kommo does not offer a built-in connector to Airtable. The Airtable Marketplace has integrations with Salesforce and HubSpot, but not with Kommo. This is not accidental: Airtable positions itself as a flexible database, not a CRM ecosystem, so partner integrations target the enterprise stack.
But the main problem is not the missing connector. The problem is that even if it existed, it would not cover a two-way scenario with configurable logic:
- Field mapping between Kommo (
custom_fields_values) and Airtable (fieldsobject) is non-trivial: data types, pipeline stage enum values, multi-selects - all of this requires conversion. - Zapier and Make pass data via polling or a simple webhook, but do not support idempotent upsert operations by an external key. On failure or duplicate event, Airtable creates a duplicate record.
- Business logic is often more complex than “field A -> field B”: you need to update Airtable only on certain statuses, enrich the record with data from a third source, or skip test deals.
Upsert - an operation that updates a record if it exists, or creates a new one if it does not. In the Airtable API this is the performUpsert parameter with fieldsToMergeOn - the key field for idempotency.
What the integration handles
Kommo webhook -> your endpoint -> Airtable API upsert by external_id
Kommo sends a webhook when a deal stage changes (leads.status in the payload). Your middleware accepts the POST in x-www-form-urlencoded format, extracts the deal id, requests the full data via GET /api/v4/leads/{id}, builds a fields object for Airtable, and calls PATCH https://api.airtable.com/v0/{baseId}/{tableIdOrName}/records with the performUpsert parameter.
The idempotency key is kommo_deal_id, stored in Airtable as a plain numeric field. In the request:
{
"records": [
{
"fields": {
"Kommo Deal ID": 123456,
"Deal Name": "Acme Corp - Enterprise",
"Stage": "Negotiation",
"Amount": 15000,
"Manager": "Ivan Petrov"
}
}
],
"performUpsert": {
"fieldsToMergeOn": ["Kommo Deal ID"]
}
}
Airtable returns createdRecords or updatedRecords in the response - you can use this to log the result. Authorization: Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN header. Rate limit: 5 requests per second per base; on exceeding it you get HTTP 429 and need exponential backoff with a pause of 30+ seconds.
The Kommo webhook is configured in Settings -> Integrations -> Web hooks. Select the “Lead stage (status) changed” event and provide your endpoint URL. The payload arrives as x-www-form-urlencoded and must be handled synchronously - respond within 2 seconds, otherwise Kommo will retry (up to 5 times).
Reverse sync: Airtable Automation -> your endpoint -> Kommo API deal update
Airtable supports built-in Automations: a trigger on field change + a Send HTTP request action. When the operations team updates a status in Airtable (for example, “Onboarding Complete”), the automation fires and sends JSON to your endpoint.
The endpoint receives the data, maps it to Kommo custom fields, and calls:
PATCH https://{subdomain}.kommo.com/api/v4/leads/{id}
With the body:
[
{
"id": 123456,
"custom_fields_values": [
{
"field_id": 789012,
"values": [{"value": "Onboarding Complete"}]
}
]
}
]
Kommo API uses OAuth 2.0 or a long-lived Integration Token. field_id is the numeric ID of the custom field, which must be retrieved in advance via GET /api/v4/leads/custom_fields.
Idempotency and duplicate protection
Both directions must be idempotent: a repeated call with the same data must not create a duplicate and must not produce an error.
For Airtable this is guaranteed by performUpsert - on a repeated webhook from Kommo the record is simply updated. For Kommo, a PATCH request on an existing id is also idempotent by nature.
Additional protection: store last_event_ts of the last processed event and skip events with an older timestamp. This closes the scenario where Kommo resends a webhook after a timeout.
Step-by-step flow
- Kommo webhook - Settings -> Integrations -> Web hooks -> “Lead stage (status) changed” event -> URL of your middleware
- Middleware receives payload - parses
x-www-form-urlencoded, extractsleads[status][0][id]andleads[status][0][status_id] - GET /api/v4/leads/{id} - fetches the full deal data: name, amount, owner, custom fields
- Field mapping - converts Kommo
status_idto a string value for Airtable, numeric fields -> numbers, text -> text - PATCH Airtable -
https://api.airtable.com/v0/{baseId}/{tableId}/recordswithperformUpserton theKommo Deal IDfield. Authorization viaAuthorization: Bearer PAT_... - Log the result -
createdRecordsvsupdatedRecordsin the Airtable response, retry on HTTP 429 - Airtable Automation - trigger on the relevant field change -> Send HTTP request -> your endpoint
- Reverse mapping - endpoint receives Airtable payload, builds
custom_fields_valuesfor Kommo - PATCH /api/v4/leads/{id} - updates the deal in Kommo by
kommo_deal_idfrom Airtable - Deduplication - timestamp check, ignoring stale events
Infrastructure: any lightweight HTTP server (Python/FastAPI, Node.js/Express, Go). Hosting - Railway, Render, or a Lambda function. Data volume is small - 1 request per event; at 100 deals per day that is about 200 API calls total, well within rate limits.
Real-world case with numbers
A company of 22 people - sales work in Kommo, the operations team (onboarding, project management) runs Airtable. Before the integration: manual sync took 30-45 minutes per day for two employees, data transfer lag ranged from several hours to a full day, systematic errors in deal amounts (different input formats in the two systems).
After launching the custom sync through Exceltic.dev:
- Delay between a status change in Kommo and the update appearing in Airtable - up to 5 seconds (webhook processing time + API call)
- Manual sync time - 0 (the task no longer exists)
- Duplicates during testing on 2000 events in the first month - 0, thanks to
performUpsertand timestamp deduplication - Development and launch timeline - 3 weeks, including custom field mapping, Airtable Automation setup, and testing
A “filtering” requirement was also solved: test deals and deals tagged “internal” are not synced to Airtable - business logic that a no-code tool cannot implement without workarounds.
Who this integration is for
This architecture makes sense for companies where:
- Sales are run in Kommo, operations (onboarding, delivery, project management) are in Airtable
- Deal volume is 50+ per month, at which point manual sync is noticeably costly
- Two-way connection is needed: Kommo must see updates from Airtable, and vice versa
- Zapier or Make have already been tried but the cost at volume was too high, or duplicates and data loss occurred on failures
Less suitable if sync is needed in only one direction and without complex mapping - in that case Zapier may cover the need more cheaply.
Related scenarios we have implemented: Kommo + Google Sheets with the same upsert logic, and Kommo + Jira for passing tasks between teams. The core principle is the same across all of them - middleware with idempotent writes by external key.
If you want to understand what custom integration tools exist in the Kommo ecosystem in general, read the custom integrations for Kommo CRM overview - it covers patterns and limitations.
Term: Personal Access Token (PAT) - an authorization token for the Airtable API, replacing the old API Key. Created at airtable.com/account, passed in the Authorization: Bearer PAT_... header, has configurable scopes.
Frequently asked questions
Is a server required for this integration?
Yes, an intermediate endpoint - your middleware - is required. This does not have to be a full server: a Lambda function (AWS, Cloudflare Workers) or a simple app on Railway/Render works fine. The free tiers on these platforms are sufficient for 100-300 requests per day. A fully serverless approach works well: the function starts only on an incoming webhook, and the cost is near zero at moderate volumes.
What happens if Kommo sends a webhook and Airtable does not respond?
Kommo retries delivery up to 5 times with increasing intervals. If your endpoint did not respond with a 200-299 code within 2 seconds, Kommo will try again. On the Airtable side: if you receive HTTP 429 (exceeding the 5 req/s limit), implement exponential backoff - wait 30+ seconds before retrying. In a typical project, a queue of 10-20 events and retry logic with 3 attempts is sufficient.
Can you sync only specific deals rather than all of them?
Yes, this is a standard part of middleware logic. Kommo webhooks arrive for all deals in the account, but your code filters by pipeline_id, status_id, tags, or custom fields. For example, sync only deals from the “Enterprise” pipeline or only when transitioning to “Won” or “In Progress” statuses. This cannot be configured on the Kommo webhook side itself - only at the handler level.
How do you get the field_id of custom fields in Kommo?
Through the API: GET https://{subdomain}.kommo.com/api/v4/leads/custom_fields - returns a list of all custom fields with their id, name, and type. Do this once at the start of the project and lock down the mapping. Fields do not change ID when renamed, so the mapping is stable.
Does the Airtable API support attachments and linked records between tables?
Yes. Attachments (attachments) are passed as an array of objects with url. Linked records (linkedRecord) are passed as an array of record IDs from the linked table. For most Kommo sync scenarios these types are not needed: text fields, numbers, and single select are sufficient. If you need a link to a client table, sync the contact as a separate call and pass its record ID into the deal field.
Next steps
If you currently have:
- Operations and sales working in separate tools with data diverging
- Already tried Zapier/Make - too expensive at volume, or duplicates and losses on failures
- Need two-way sync with non-standard filtering logic
Describe the problem to the Exceltic.dev team. We will review your stack: which fields need to sync, in which directions, what event volume to expect. We will estimate the scope of work and propose a concrete architecture.
Technical documentation if you want to explore on your own: Airtable Web API and Kommo Webhooks.