Smartsheet is an enterprise work management platform that combines the familiar spreadsheet interface with project management capabilities: Gantt charts, resource management, automation, reporting, and integrations. It is popular in enterprise environments where teams are accustomed to Excel but need collaboration and progress tracking. Unlike Jira or Asana, Smartsheet is closer to a spreadsheet-project — indispensable where project data needs to be viewed in tabular form and exported to Excel. Without Kommo integration, Won deal data is transferred to Smartsheet manually — 15–20 minutes with a high risk of errors.
Smartsheet vs Jira vs Asana for Implementation Teams
| Parameter | Smartsheet | Jira | Asana |
|---|---|---|---|
| Target audience | Enterprise non-tech | Tech teams | Mixed teams |
| Tabular interface | Yes (primary) | No | No |
| Gantt | Built-in | Plugin | Built-in |
| Resource planning | Yes | Limited | Yes (Business+) |
| Best for | Operations, PMO, construction | Development | Marketing, product |
Smartsheet is chosen by companies where the PM team works in spreadsheets rather than kanban boards — professional services, construction, enterprise IT.
Architecture: What Gets Synchronised
Kommo -> Smartsheet: — Won -> create a new row in the project Sheet (name, client, amount, PM, dates) — Won -> create child rows (task checklist) from a standard template
Smartsheet -> Kommo: — Row status change (In Progress -> Complete) -> Note in deal — Webhook on “Due Date” cell -> Task in Kommo 7 days before deadline
Smartsheet REST API: Creating a Row in a Sheet
Base URL: https://api.smartsheet.com/2.0. Authentication: Authorization: Bearer {token} (Personal Access Token from Smartsheet -> Account -> Apps & Integrations -> API Access -> Generate new access token).
import requests
SS_TOKEN = "your_personal_access_token"
SS_BASE = "https://api.smartsheet.com/2.0"
SS_HEADERS = {
"Authorization": f"Bearer {SS_TOKEN}",
"Content-Type": "application/json",
}
SS_SHEET_ID = "your_sheet_id" # from sheet URL: smartsheet.com/sheets/{ID}
def get_sheet_columns(sheet_id: str) -> dict:
# Get column title -> column id mapping
resp = requests.get(
f"{SS_BASE}/sheets/{sheet_id}",
headers=SS_HEADERS,
)
resp.raise_for_status()
cols = resp.json().get("columns", [])
return {col["title"]: col["id"] for col in cols}
def add_row_to_sheet(sheet_id: str, col_map: dict,
row_data: dict, parent_row_id: int = None) -> dict:
cells = [
{"columnId": col_map[key], "value": value}
for key, value in row_data.items()
if key in col_map
]
row = {"cells": cells, "toBottom": True}
if parent_row_id:
row["parentId"] = parent_row_id
resp = requests.post(
f"{SS_BASE}/sheets/{sheet_id}/rows",
headers=SS_HEADERS,
json={"rows": [row]},
)
resp.raise_for_status()
return resp.json()
# Standard onboarding task checklist after Won
ONBOARDING_TASKS = [
"Kickoff call with client",
"Requirements gathering",
"Environment setup",
"First delivery",
"UAT (user acceptance testing)",
"Go-live",
"Final documentation",
]
def on_kommo_deal_won(lead: dict, contact: dict):
company = get_custom_field(lead, COMPANY_FIELD_ID) or contact.get("name", "")
manager = get_custom_field(lead, PM_FIELD_ID) or ""
value = lead.get("price", 0)
col_map = get_sheet_columns(SS_SHEET_ID)
row_data = {
"Project Name": f"{company} - {lead.get('name', '')}",
"Client": company,
"Deal Value": value,
"PM": manager,
"Status": "Not Started",
"Start Date": "",
"CRM Deal ID": str(lead["id"]),
}
result = add_row_to_sheet(SS_SHEET_ID, col_map, row_data)
parent_id = result["result"][0]["id"]
for task in ONBOARDING_TASKS:
add_row_to_sheet(SS_SHEET_ID, col_map,
{"Project Name": task, "Status": "Not Started"},
parent_row_id=parent_id)
sheet_url = f"https://app.smartsheet.com/sheets/{SS_SHEET_ID}"
save_to_kommo_deal(lead["id"], {"smartsheet_row_id": parent_id})
create_kommo_note(
lead["id"],
f"Smartsheet: project created, {len(ONBOARDING_TASKS)} tasks -> {sheet_url}",
)
Webhook: Smartsheet -> Kommo
Smartsheet supports webhooks on cell changes. Setup: POST /webhooks with callbackUrl and scopeObjectId (Sheet ID).
def create_smartsheet_webhook(sheet_id: str, callback_url: str) -> dict:
payload = {
"name": "Kommo sync",
"callbackUrl": callback_url,
"scope": "sheet",
"scopeObjectId": int(sheet_id),
"events": ["*.*"],
"version": 1,
}
resp = requests.post(
f"{SS_BASE}/webhooks",
headers=SS_HEADERS,
json=payload,
)
resp.raise_for_status()
return resp.json()
@app.route("/webhooks/smartsheet", methods=["POST"])
def smartsheet_webhook():
# Smartsheet sends a challenge on initial setup
challenge = request.headers.get("Smartsheet-Hook-Challenge")
if challenge:
return jsonify({"smartsheetHookResponse": challenge})
payload = request.json
events = payload.get("events", [])
for event in events:
if event.get("objectType") != "cell":
continue
row_id = event.get("rowId")
col_id = event.get("columnId")
new_val = event.get("newValue", "")
lead_id = find_kommo_deal_by_smartsheet_row(row_id)
if not lead_id:
continue
col_name = get_column_name(SS_SHEET_ID, col_id)
if col_name == "Status" and new_val == "Complete":
create_kommo_note(lead_id, "Smartsheet: project completed")
elif col_name == "Status" and new_val == "In Progress":
create_kommo_note(lead_id, "Smartsheet: project in progress")
elif col_name == "Due Date" and new_val:
schedule_kommo_task(lead_id,
"Smartsheet: project deadline in 7 days - check status",
due_days=7)
return "", 200
Project Template: Automation via Smartsheet
Smartsheet supports automations (Automations in UI): when a row status changes -> send notification -> assign a new owner. For the Kommo integration, the key point is: Smartsheet automations work independently, the webhook only informs Kommo.
To create a project from a template (template Sheet) instead of manually creating rows:
def copy_sheet_as_template(template_sheet_id: str, new_name: str) -> dict:
# Create a copy of the template sheet as a new project
resp = requests.post(
f"{SS_BASE}/sheets/{template_sheet_id}/copy",
headers=SS_HEADERS,
json={
"destinationType": "home",
"newName": new_name,
"include": ["data", "attachments", "automations"],
},
)
resp.raise_for_status()
return resp.json()
Real-World Case
Professional services company (US, 60 employees, Kommo + Smartsheet):
- Before: Won -> project coordinator receives a Slack assignment -> manually creates a row in Smartsheet -> fills in 12 fields from deal data -> creates 8 standard tasks. 30–45 minutes. Errors in contract amounts (20% of rows).
- After: Won -> Python webhook -> row + 7 child tasks in 3 seconds. Data from Kommo (client, amount, PM) is transferred without human involvement.
- Additionally: “Complete” in Smartsheet -> Note in Kommo -> manager initiates a renewal conversation. The delay between project completion and the renewal conversation shortened from 3 weeks to 2 days.
Who This Is Relevant For
- Professional services and consulting where every Won means a new project with a checklist
- Enterprise companies where the PM team works in Smartsheet and sales in Kommo
- Construction, IT implementations, agencies — any project-based business with a fixed set of stages
- Companies that need to view project data in tabular format and produce summary reports
Frequently Asked Questions
Smartsheet Sheet vs Grid vs Project — which to use for integration?
For Kommo API integration, the sheet type does not matter — all work goes through the universal endpoint POST /sheets/{id}/rows. The difference is only in sheet settings (Grid — plain table, Project — with Gantt and dependencies). For project management with Gantt, choose the “Project” type when creating a Sheet in the UI; the API does not change.
How do I get the Sheet ID for the Smartsheet API?
Open the required Sheet in the browser -> the URL looks like https://app.smartsheet.com/sheets/XXXXXXXXXXXXXXXX -> the last segment is the Sheet ID (16 digits). Or via API: GET /sheets returns a list of all sheets with their IDs.
Smartsheet Column ID — how do I map fields?
GET /sheets/{id} returns the full Sheet including a columns array with id, title, and type. The get_sheet_columns() function in the example above creates a {title: id} dictionary. Column ID is a number that does not change when a column is renamed. It is better to build the mapping by ID rather than name — in case the team renames a column in Smartsheet.
Can a project be created from a Smartsheet template via API?
Yes, via POST /sheets/{templateId}/copy. A template is a regular Sheet with example rows. When copied via API, a new Sheet is created with the same columns and (optionally) data. After copying — update the required rows via PUT /sheets/{newSheetId}/rows.
Summary
- API: Bearer token (Personal Access Token), base URL
https://api.smartsheet.com/2.0 - Won ->
POST /sheets/{id}/rowscreates a project row + child task rows get_sheet_columns()— always build mapping via API, do not hardcode column IDs- Webhook:
POST /webhooks-> challenge handshake -> cell change events -> Kommo Notes - Template:
POST /sheets/{templateId}/copycreates a new Sheet from the template for each project
If you have Kommo and Smartsheet and Won requires project creation with a checklist — describe your sheet structure and standard task set. Exceltic.dev will configure the integration with two-way synchronisation.