Kommo + Chargebee: automatic subscription creation from won deals
Chargebee is a subscription management platform for SaaS with a REST API on Basic Auth. Without the Kommo integration, a manager manually creates a customer in Chargebee after Won, selects a plan, starts a subscription — and forgets to update the CRM. With the integration, Won in Kommo triggers the entire chain automatically: a Customer is created in Chargebee, the subscription is activated, and payment status and cancellation events come back into the deal card.
What the Kommo + Chargebee combination delivers
Without integration: — Won in Kommo -> manager manually opens Chargebee, creates a customer, configures the plan — Average time from Won to subscription activation — 1–3 hours — When a subscription is cancelled in Chargebee, Kommo does not know — the deal stays as Won without an update — Billing and the manager work in different systems with no unified view
With integration:
— Won -> Customer + Subscription in Chargebee within 3 minutes
— payment_succeeded -> Note in Kommo: “Payment received, $X”
— subscription_cancelled -> task for manager + field change in deal
— invoice_generated -> invoice link in Kommo
What gets synchronized
Kommo -> Chargebee: — Contact name and email -> Customer in Chargebee — Plan from custom field -> Subscription plan ID — Deal amount -> billing amount (if non-standard plan) — Deal ID -> customer metadata (for reverse tracing)
Chargebee -> Kommo:
— payment_succeeded -> Note with amount and date
— invoice_generated -> Note with invoice link
— subscription_cancelled -> custom field subscription_status = cancelled + task for manager
— subscription_renewed -> Note “Subscription renewed”
Architecture
Kommo Webhook: deal moved to Won
↓ Backend
1. GET /api/v4/leads/{id} + contacts
-> name, email, plan from custom fields
2. Chargebee: POST /api/v2/customers
-> first_name, last_name, email, cf_kommo_deal_id
3. Chargebee: POST /api/v2/subscriptions
-> customer_id + plan_id + billing_cycles
-> receive subscription_id
4. Kommo: PATCH /leads/{id}
-> chargebee_customer_id, subscription_id, subscription_status = active
Chargebee Webhook: payment_succeeded
↓ Backend
1. From payload: customer_id, amount, invoice_id
2. Find deal_id by cf_kommo_deal_id in Customer
3. Kommo: POST /leads/{deal_id}/notes
-> "Payment received: ${amount}. Invoice: {invoice_url}"
Chargebee Webhook: subscription_cancelled
↓ Backend
1. From payload: customer_id, cancellation_reason
2. Find deal_id
3. Kommo: PATCH /leads/{deal_id}
-> subscription_status = cancelled
4. Kommo: POST /tasks
-> task for manager: "Subscription cancelled: {reason}"
Chargebee REST API: key requests
Base URL: https://{site}.chargebee.com/api/v2/. Authentication: Basic Auth, username = API_KEY, password — empty.
Create a customer:
import chargebee
chargebee.configure(api_key='your_api_key', site='your-site')
def create_customer(email: str, first_name: str, last_name: str,
deal_id: int) -> str:
result = chargebee.Customer.create({
'email': email,
'first_name': first_name,
'last_name': last_name,
'cf_kommo_deal_id': str(deal_id) # custom field for tracing
})
return result.customer.id
Create a subscription:
def create_subscription(customer_id: str, plan_id: str,
billing_cycles: int = None) -> dict:
params = {
'customer_id': customer_id,
'subscription_items': [{
'item_price_id': plan_id # e.g. 'pro-monthly-usd'
}]
}
if billing_cycles:
params['subscription_items'][0]['billing_cycles'] = billing_cycles
result = chargebee.Subscription.create_with_items(params)
sub = result.subscription
return {
'id': sub.id,
'status': sub.status,
'current_term_end': sub.current_term_end
}
Handling Chargebee webhooks:
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhooks/chargebee', methods=['POST'])
def chargebee_webhook():
payload = request.json
event_type = payload.get('event_type')
content = payload.get('content', {})
if event_type == 'payment_succeeded':
transaction = content.get('transaction', {})
customer_id = transaction.get('customer_id')
amount = transaction.get('amount', 0) / 100 # cents -> dollars
deal_id = get_deal_id_by_customer(customer_id)
if deal_id:
create_kommo_note(deal_id, f'Chargebee: payment received ${amount:.2f}')
elif event_type == 'subscription_cancelled':
subscription = content.get('subscription', {})
customer_id = subscription.get('customer_id')
reason = subscription.get('cancel_reason', 'not specified')
deal_id = get_deal_id_by_customer(customer_id)
if deal_id:
update_kommo_deal(deal_id, {'subscription_status': 'cancelled'})
create_kommo_task(deal_id, f'Chargebee subscription cancelled. Reason: {reason}')
elif event_type == 'invoice_generated':
invoice = content.get('invoice', {})
customer_id = invoice.get('customer_id')
invoice_url = invoice.get('invoice_url', '')
total = invoice.get('total', 0) / 100
deal_id = get_deal_id_by_customer(customer_id)
if deal_id:
create_kommo_note(deal_id, f'Chargebee invoice: ${total:.2f}. Link: {invoice_url}')
return '', 200
Idempotency: Chargebee may retry a webhook on error. Store event_id from the payload and check it before processing — otherwise the Note will be created twice.
Kommo plan -> Chargebee mapping
A Chargebee plan (plan_id) follows the format {plan}-{period}-{currency}, e.g. pro-monthly-usd. Linking it to a Kommo custom field:
PLAN_MAP = {
'Starter': 'starter-monthly-usd',
'Pro': 'pro-monthly-usd',
'Enterprise': 'enterprise-monthly-usd',
'Pro Annual': 'pro-yearly-usd'
}
def get_plan_id(kommo_tariff_field: str) -> str:
return PLAN_MAP.get(kommo_tariff_field, 'pro-monthly-usd')
Real case
B2B SaaS (EU market, 40–60 new customers per quarter, Kommo + Chargebee + Stripe):
- Before: after Won, a manager spent 15–30 minutes creating a customer in Chargebee. Errors in the plan or missed billing_cycles were common — clients received open-ended subscriptions.
- After: Won -> subscription active within 5 minutes. The manager never opens Chargebee. On first payment — automatic Note in Kommo; on cancellation — a task with the reason.
- Additionally: Customer Success sees the full payment history in the deal card — without needing access to Chargebee.
A similar pattern for Stripe — there it uses payment links; here it is full subscription management via Chargebee.
Who should use this
- SaaS companies with Chargebee as their subscription management platform
- Need to connect Won in the CRM to subscription activation without a manual step
- Customer Success should see subscription status and payment history in Kommo
- 20+ new subscriptions per month — manual work becomes unprofitable
Frequently asked questions
Chargebee API — is OAuth needed or is an API key enough?
For server-side integrations — API Key via Basic Auth: key as username, empty password. OAuth is not needed. The key is created in Chargebee: Settings -> Configure Chargebee -> API Keys.
How do you configure a webhook in Chargebee?
Settings -> Configure Chargebee -> Webhooks -> Add Webhook URL. Select events: payment_succeeded, subscription_cancelled, invoice_generated, subscription_renewed. Chargebee signs the payload via HMAC-SHA256 with the Chargebee-Webhook-Signature header for verification.
Chargebee vs Stripe Billing for Kommo integration?
Both work with an API Key. Chargebee specializes in subscription management: plan changes, pause, dunning management, revenue recognition. Stripe Billing is simpler with fewer out-of-the-box features. If you use Chargebee — integrate via the Chargebee API. If you only use Stripe — via Stripe Payment Links or the Stripe Billing API.
How do you store the customer_id -> deal_id link?
Two options: custom field in Chargebee Customer (cf_kommo_deal_id) — available from the webhook payload, no separate storage needed. Or a DB table {chargebee_customer_id -> kommo_deal_id}. The first option is simpler and works without additional storage.
What if a client upgrades their plan?
The subscription_changed webhook contains the old and new plan_id. Update the custom field in Kommo and create a Note: “Plan changed: {old_plan} -> {new_plan}”.
Summary
- Chargebee REST API: Basic Auth (API key), Python SDK
pip install chargebee - Create Customer + Subscription on Won via
chargebee.Customer.createandSubscription.create_with_items - Webhook events:
payment_succeeded,subscription_cancelled,invoice_generated-> Notes and tasks in Kommo - Idempotency: store
event_idto prevent duplicates on retry - Typical development timeline — 1–2 weeks
If you use Chargebee and Kommo and want to automate subscription activation on deal close — describe your plan structure and billing scheme. Exceltic.dev will configure the mapping and payment event handling.