Webhooks
Send signed JSON to a URL of your choice when something happens in the CRM (an opportunity is won, a new company is added, a form is submitted…). Zapier, Make, n8n, and Pipedream use the same mechanism.
A webhook (outbound hook) is a way to push CRM events to your system: instead of constantly polling the API, you receive an HTTP POST when an event happens. You set it up on the Settings → Apps (Ayarlar → Uygulamalar) page; no code required.
Setup
- 1
Open the connection
In Settings → Apps (Ayarlar → Uygulamalar), select Webhook (Web kancası) (or the Zapier, Make, n8n, or Pipedream card) and click Connect (Bağla).
- 2
Enter the URL
Paste the
https://URL that events should be sent to. You get this URL from "Webhooks by Zapier → Catch Hook" in Zapier, "Webhooks → Custom webhook" in Make, the "Webhook" node in n8n, or the "HTTP / Webhook" trigger in Pipedream. - 3
Choose events
Select the events that should trigger a delivery. The connection card shows a signing key; store it so the receiving side can verify that requests really come from the CRM.
- 4
Test it
Test connection (Bağlantıyı dene) sends a test delivery with
event: "test"to your receiver. The result of the latest delivery (HTTP status code or error) appears on the card.
Events
| Event | When | data fields |
|---|---|---|
opp_created |
A new opportunity was created | id, rid, name, customer, customer_id, stage, stage_label, value, currency, owner |
opp_stage |
An opportunity's stage changed (the title shows the old → new stage) | Opportunity fields |
opp_won |
An opportunity was won (Win) |
Opportunity fields |
opp_lost |
An opportunity was lost (Lost) |
Opportunity fields |
customer_created |
New company | id, rid, name, status, source, city |
contact_created |
New person (except those created automatically from email) | id, name, email, phone, title, customer, customer_id |
lead_created |
New fair lead | id, company, contact, email, interest |
visit_created |
Activity / visit logged | id, customer, type, date, next_action, note |
ticket_created |
New support ticket | id, subject, priority, who |
form_submitted |
Website form / Typeform / Tally submission | form, company, name, email, phone, customer_id, task_id, new_customer |
Events are sent for every change, whether it comes from the web interface, the mobile app, the API, MCP, workflows, or inbound hooks. There are two exceptions:
- Sample data records don't send events.
- If a single operation produces more than 25 events (e.g. a bulk import from Excel), no events are sent; a note is added to the audit log instead.
Payload
POST /sizin/adresiniz HTTP/1.1
Content-Type: application/json
X-Solk-Event: opp_won
X-Solk-Signature: sha256=5d1c0a3e9b…{
"event": "opp_won",
"title": "Fırsat kazanıldı",
"text": "Kuzey Plastik Sanayi · Streç film tedariki · 338.400 € · Sorumlu: Deniz Aksoy",
"url": "https://ornek.solk.app/opportunities/53",
"data": {
"id": 53,
"rid": "006Xq3LmT0aZb9K",
"name": "Streç film tedariki",
"customer": "Kuzey Plastik Sanayi",
"customer_id": 31,
"stage": "Win",
"stage_label": "Win",
"value": 338400.0,
"currency": "EUR",
"owner": "Deniz Aksoy"
},
"workspace": "Örnek Kimya",
"app": "Solk CRM",
"sent_at": "2026-10-02T14:05:11"
}| Field | Description |
|---|---|
event |
Event name (see the table above; test for test deliveries). |
title, text |
Human-readable title and summary — you can post them directly to notification channels. |
url |
The record's URL in the CRM. |
data |
Event-specific structured fields. If you need the full record, fetch it from the REST API using data.id. |
workspace, app |
The installation's company name and app name. |
sent_at |
Time the delivery was sent (in the installation's local time). |
Verifying the signature
X-Solk-Signature is the HMAC-SHA256 digest of the request body (as raw bytes), computed with the signing key. Verify it before you parse the body as JSON:
import hmac, hashlib
def verify(body_bytes: bytes, signature: str, key: str) -> bool:
expected = "sha256=" + hmac.new(key.encode(), body_bytes, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
# Flask
@app.post("/solk")
def solk():
if not verify(request.get_data(), request.headers.get("X-Solk-Signature"), SIGNING_KEY):
abort(401)
event = request.get_json()
...import crypto from "node:crypto";
import express from "express";
const app = express();
app.post("/solk", express.raw({ type: "application/json" }), (req, res) => {
const expected = "sha256=" + crypto.createHmac("sha256", process.env.SOLK_SIGNING_KEY)
.update(req.body).digest("hex");
const signature = req.get("X-Solk-Signature") || "";
if (signature.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
res.sendStatus(204);
});$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, getenv('SOLK_SIGNING_KEY'));
if (!hash_equals($expected, $_SERVER['HTTP_X_SOLK_SIGNATURE'] ?? '')) {
http_response_code(401); exit;
}
$event = json_decode($body, true);Delivery
- Deliveries are sent in the background, independently of the request; CRM users don't wait.
- The timeout is 8 seconds. Your receiver must return a
2xx; queue long-running work and respond immediately. - There are no retries. A failed delivery shows up as the latest status on the connection card. If you can't afford to miss events, sync periodically from the API (e.g.
GET /api/v1/opportunities?sort=update). - Ordering isn't guaranteed; sort events for the same record by
sent_at.
Channels
Slack, Microsoft Teams, Google Chat, Discord, and Telegram connections send the same events in the channel's own message format (Slack text, a Teams Adaptive Card…); the signature header is present only for webhook, Zapier, Make, n8n, and Pipedream connections. Notion, Airtable, Google Sheets, Asana, ClickUp, Linear, and Mailchimp connections instead create a record in that app from the event. Details: Apps.
Writing back to the CRM
If your workflow needs to create or update records in the CRM (e.g. "invoice paid → complete task" in Zapier), create an API key in Settings → Developers (Ayarlar → Geliştiriciler) and call the REST API from the HTTP step in Zapier / Make / n8n with the Authorization: Bearer sk_… header. The no-code way to push data in from outside is inbound hooks.