Vonage (acquired by Ericsson) is a Communications API platform for SMS, voice calls, and messaging. Coverage: 200+ countries, EU number support (Germany, Netherlands, UK). There is no native integration with Kommo - we build via Vonage Messages API v1 and Voice API.
What we’re building
SMS scenarios:
- When a deal moves to “Proposal Sent” -> SMS to the client with a reminder
- Inbound SMS from the client -> Note in Kommo + task for the manager
Voice scenarios:
- Outbound call from Kommo -> Vonage Voice API -> call recording as a Note
Vonage authentication
Vonage uses two methods: API Key + Secret (for SMS) and JWT (for Voice API).
API Key + Secret - for Messages API:
import requests, base64
VONAGE_API_KEY = "your_api_key"
VONAGE_API_SECRET = "your_api_secret"
# Messages API uses Basic Auth
credentials = base64.b64encode(f"{VONAGE_API_KEY}:{VONAGE_API_SECRET}".encode()).decode()
msg_headers = {
"Authorization": f"Basic {credentials}",
"Content-Type": "application/json",
}
JWT - for Voice API:
import jwt, time, uuid
VONAGE_APPLICATION_ID = "your_app_id"
VONAGE_PRIVATE_KEY_PATH = "private.key" # download from Vonage Dashboard
def generate_jwt() -> str:
private_key = open(VONAGE_PRIVATE_KEY_PATH, "rb").read()
payload = {
"application_id": VONAGE_APPLICATION_ID,
"iat": int(time.time()),
"jti": str(uuid.uuid4()),
"exp": int(time.time()) + 3600,
}
return jwt.encode(payload, private_key, algorithm="RS256")
Voice API requires an RSA private key from a Vonage Application. Messages API works only with API Key + Secret.
Sending an SMS to a client
def send_sms(to_number: str, text: str, from_number: str = "EXCELTIC") -> dict:
"""Send SMS via Vonage Messages API v1."""
payload = {
"from": from_number, # alphanumeric sender or your Vonage number
"to": to_number, # E.164 format: +49301234567
"channel": "sms",
"message_type": "text",
"text": text,
}
r = requests.post(
"https://api.nexmo.com/v1/messages",
headers=msg_headers,
json=payload,
)
r.raise_for_status()
return r.json() # {"message_uuid": "..."}
Alphanumeric sender IDs (e.g. EXCELTIC) are not supported in some countries - in the US a registered 10DLC number is required, in Germany a German virtual number is needed.
Trigger from Kommo webhook:
from flask import Flask, request
app = Flask(__name__)
@app.route("/kommo/webhook", methods=["POST"])
def kommo_webhook():
data = request.json
if "leads" not in data:
return "ok", 200
for event_type in ["update"]:
leads = data.get("leads", {}).get(event_type, [])
for lead in leads:
old_status = lead.get("old_status_id")
new_status = lead.get("status_id")
if new_status == PROPOSAL_STAGE_ID and old_status != PROPOSAL_STAGE_ID:
contact_phone = get_kommo_contact_phone(lead["id"])
if contact_phone:
deal_name = lead.get("name", "")
send_sms(
to_number=contact_phone,
text=f"Your proposal from Exceltic is ready. Check your email or reply to this message.",
)
return "ok", 200
Inbound SMS - Note in Kommo
Vonage sends inbound SMS to your Inbound Webhook URL.
@app.route("/vonage/inbound-sms", methods=["POST", "GET"])
def inbound_sms():
# Vonage sends GET or POST depending on configuration
data = request.values if request.method == "GET" else request.json or request.form
from_number = data.get("msisdn", "") # sender number
text = data.get("text", "")
message_id = data.get("messageId", "")
# Find contact by phone number in Kommo
contact = find_kommo_contact_by_phone(from_number)
if contact:
deal_id = get_active_deal(contact["id"])
if deal_id:
add_kommo_note(
deal_id=deal_id,
text=f"SMS from {from_number}: {text}",
note_type="sms",
)
return "ok", 200
Important: Vonage expects HTTP 200 in response to an inbound SMS. If the server returns an error, Vonage will retry for up to 72 hours.
Outbound call via Voice API
NCCO_BASE_URL = "https://your-service.com" # public URL for NCCO
def initiate_call(to_number: str, from_number: str, deal_id: int) -> str:
"""Start outbound call. Returns call UUID."""
payload = {
"to": [{"type": "phone", "number": to_number}],
"from": {"type": "phone", "number": from_number},
"answer_url": [f"{NCCO_BASE_URL}/vonage/ncco/{deal_id}"],
"event_url": [f"{NCCO_BASE_URL}/vonage/call-events/{deal_id}"],
"record": True,
"recording_channels": "split", # separate tracks for agent and client
}
r = requests.post(
"https://api.nexmo.com/v1/calls",
headers={"Authorization": f"Bearer {generate_jwt()}", "Content-Type": "application/json"},
json=payload,
)
r.raise_for_status()
return r.json()["uuid"]
@app.route("/vonage/ncco/<int:deal_id>")
def ncco(deal_id: int):
"""Vonage Call Control Object - call instructions."""
return jsonify([
{"action": "talk", "text": "Connecting you to an Exceltic manager."},
{"action": "connect", "from": VONAGE_FROM_NUMBER, "endpoint": [
{"type": "phone", "number": AGENT_NUMBER}
]},
{"action": "record", "eventUrl": [f"{NCCO_BASE_URL}/vonage/recording/{deal_id}"]},
])
Handling the recording event:
@app.route("/vonage/recording/<int:deal_id>", methods=["POST"])
def call_recording(deal_id: int):
data = request.json
recording_url = data.get("recording_url", "")
duration_sec = data.get("duration", 0)
note = f"Vonage call. Duration: {duration_sec}s. Recording: {recording_url}"
add_kommo_note(deal_id, note)
return "ok", 200
Call recordings are stored on Vonage servers for 30 days. The URL is available immediately after the call ends - authentication uses the same JWT.
Real case
A B2B distributor in the Netherlands was using email for initial contact, but the response rate was 18%. After adding an SMS reminder when sending a proposal:
- Response rate rose to 34% within the first 2 weeks
- Average client response time dropped from 2.3 days to 14 hours
- Inbound SMS from clients appear in Kommo without manual copying
A typical project setup takes 3-5 business days including testing EU numbers.
Who this is for
Companies with EU clients who already use or are considering SMS as a communication channel. Vonage is particularly useful for teams in DACH and Benelux - registering German and Dutch numbers goes through Vonage without complex local procedures.
For IP telephony with call recording - see also Kommo + CloudTalk and Kommo + RingCentral.
Frequently asked questions
Can WhatsApp messages be sent via Vonage?
Yes. Vonage Messages API supports WhatsApp Business as a channel. Change "channel": "sms" to "channel": "whatsapp" and pass the WhatsApp number. A WhatsApp Business Account and an approved template are required for outbound messages outside the 24-hour window.
How does alphanumeric sender ID work in Europe?
In most EU countries, alphanumeric senders (e.g. a company name instead of a number) are allowed for outbound SMS. Exceptions: France, Finland, some Baltic countries - a registered number is required there. Vonage automatically falls back to a numeric number if alphanumeric is not supported in the recipient’s country.
How does Vonage differ from Twilio?
The APIs are similar but there are differences: Vonage SMS API uses msisdn instead of from/to, and authentication is split (API Key+Secret for Messages, JWT for Voice). Twilio has broader documentation and ecosystem. Vonage has better coverage in DACH and Nordics for SMS delivery rates.
How to ensure GDPR compliance when storing SMS?
SMS content logged in Kommo as a Note falls under GDPR as personal data. Set a retention policy in Kommo: by default Notes are stored indefinitely. Vonage does not store SMS content after delivery. Delivery report logs are stored for 72 hours.
Summary
Kommo + Vonage integration covers SMS and voice calls in a single stack:
- Messages API: Basic Auth, alphanumeric sender, two-way SMS
- Voice API: JWT with RSA private key, NCCO for call control, recording with split tracks
- Inbound SMS: webhook 200 OK within 72-hour retry window
If your team works with EU clients and needs SMS as a communication tool - describe the task to Exceltic.dev. We’ll set up the integration for your stack and set of numbers.