# Inbound hooks

> Send data to the CRM through a secret URL from forms, phone systems, payment systems, data warehouses, and booking tools.

An inbound hook is a secret URL that lets an external system send data to the CRM **without credentials**. Each connection has its own URL; the random key in the URL carries both identity and authorization. You get the URL when you connect the relevant card in **Settings → Apps** (*Ayarlar → Uygulamalar*).

```text
https://ornek.solk.app/in/<app>/<secret key>      (Aircall, Stripe, Segment, data sync…)
https://ornek.solk.app/in/form/<secret key>       (website form, Typeform, Tally)
```

:::warning
A URL that contains the secret key is like a password. Enter it only in the sending system; if it leaks, get a new one with **Regenerate URL** (*Adresi yenile*) on the connection card — the old URL stops working immediately.
:::

## Common rules

- The method is `POST` and the body is JSON (form submissions can also use `application/x-www-form-urlencoded`). A `GET` request to the same URL returns a short JSON response confirming that the connection works.
- Records are created on behalf of the connection's **owner** (the user who set up the connection, or the user selected on the card); if the event's own user (e.g. the email of the rep who made the call) matches a user, that user is used instead.
- If the same event arrives twice (same external ID), it isn't processed a second time: `{"ok": true, "skipped": "zaten işlendi"}` ("already processed").
- Rate limits are **per hour**, per connection: Segment 3000, data sync / Aircall / RingCentral / Stripe 600, all others 120 requests. If you exceed the limit, you get `429`.
- The URL of a disabled or deleted connection returns `404`.

## Website form {#form}

Connect the contact / quote form on your own website directly to the CRM. Each submission:

1. Finds an existing company by name, or creates a **prospect company** if none exists (source: Web formu),
2. Links the person to the company (adding the person if the email isn't on file),
3. Creates a **high-priority task due today** for the connection owner and sends a notification,
4. Forwards the `form_submitted` event to apps.

Fields are recognized by their names, which can be in Turkish or English:

| CRM field | Recognized field names |
|---|---|
| Company | `firma`, `şirket`, `company`, `kurum`, `organization` |
| Full name | `ad soyad`, `adınız`, `isim`, `name`, `full name`, `yetkili` |
| Email | `e-posta`, `eposta`, `email`, `mail` (the value must contain `@`) |
| Phone | `telefon`, `phone`, `tel`, `gsm`, `cep` |
| City | `şehir`, `il`, `city` |
| Job title | `unvan`, `görev`, `title`, `pozisyon` |
| Message | `mesaj`, `message`, `not`, `açıklama`, `talep`, `konu` |

Unrecognized fields aren't lost either: all fields are written to the task details as "label: value" lines.

:::code
```html HTML form
<form action="https://ornek.solk.app/in/form/GIZLI_ANAHTAR" method="post">
  <input name="firma" placeholder="Company" required>
  <input name="ad soyad" placeholder="Your name">
  <input name="e-posta" type="email" placeholder="Email" required>
  <input name="telefon" placeholder="Phone">
  <textarea name="mesaj" placeholder="Your message"></textarea>
  <!-- page to redirect to after submission (optional) -->
  <input type="hidden" name="_next" value="https://firmaniz.com/tesekkurler">
  <button>Submit</button>
</form>
```
```bash cURL (JSON)
curl https://ornek.solk.app/in/form/GIZLI_ANAHTAR \
  -H "Content-Type: application/json" \
  -d '{"company": "Anadolu Gıda", "name": "Murat Er", "email": "murat@anadolugida.com.tr", "message": "Aylık 5 ton streç film"}'
```
:::

The response is `{"ok": true, "customer_id": 42, "task_id": 118}`. If the HTML form sets `_next`, the user is redirected to that page.

**Typeform** and **Tally** use the same URL structure; paste the URL into the form's webhook settings. If you enter the signing secret on the card, the `Typeform-Signature` / `Tally-Signature` headers are verified and unsigned requests get `401`.

## Data sync {#sync}

Send companies and people from your data warehouse, ERP, or another CRM in bulk to **create or update** them. Works with Census, Hightouch, Airbyte, your own script, or Zapier.

```bash
curl "https://ornek.solk.app/in/sync/GIZLI_ANAHTAR?obj=customer" \
  -H "Content-Type: application/json" \
  -d '{"rows": [
        {"external_id": "ERP-1042", "name": "Kuzey Plastik Sanayi", "website": "kuzeyplastik.com.tr", "city": "Bursa", "industry": "Plastik", "status": "AC"},
        {"external_id": "ERP-1043", "name": "Anadolu Gıda Ambalaj", "phone": "+90 332 555 10 20"}
      ]}'
```

```json
{ "ok": true, "created": 1, "updated": 1, "errors": [] }
```

- Choose the object with `?obj=customer` / `?obj=contact` or with `"object"` in the body; if you omit it, rows that have an `email` and no `industry` are treated as people.
- The body can be an array, a `rows` / `records` / `batch` / `data` field, or a single object. Up to **500 rows** per request.
- Matching order — company: `external_id` (if sent before) → name → website domain. Person: `external_id` → email.
- Company fields: `name`/`company`, `website`/`domain`, `phone`, `city`, `industry`/`sector`, `address`, `status` (`AC`/`Prospect`). Person fields: `name` (or `first_name` + `last_name`), `email`, `phone`/`mobile`, `title`/`job_title`, `department`, and `company` or `company_external_id` for the company.
- Empty values don't erase existing data; only populated fields are written.

## Segment {#segment}

In Segment, add a **Webhooks (Actions)** destination and enter the URL.

- `identify` → creates or updates the person (and the company, if `traits.company` is present); `userId` is stored as the external ID.
- `group` → creates or updates the company (`groupId`, `traits.name`, `website`, `industry`).
- `track` → the event names you select on the card (e.g. `Demo Requested, Trial Started`) are added as notes on the person's company.

In batch sends (`batch`), up to 100 events are processed per request.

## Phone: Aircall and RingCentral {#calls}

In the **Aircall** webhook, select the `call.ended` and `call.voicemail_left` events. For **RingCentral** and other phone systems, send this flat body via Zapier / Make:

```json
{
  "id": "rc-88231",
  "direction": "outbound",
  "number": "+90 224 555 01 02",
  "result": "answered",
  "duration": 312,
  "started_at": "2026-10-02T10:41:00+03:00",
  "user_email": "deniz@ornekkimya.com.tr",
  "recording_url": "https://…",
  "notes": "Fiyat görüşüldü"
}
```

- If the number matches a person or company, a **phone call** activity is created (duration, direction, recording link, note).
- For a missed inbound call, a **"Call back"** (*Geri ara*) task is created for the owner (high priority, with the voicemail link).
- If the number is unknown, a "link the record to a company" task is created.

## Stripe {#stripe}

In the Stripe Dashboard, add the URL as a webhook endpoint and select the `invoice.paid`, `invoice.payment_failed`, `customer.subscription.deleted`, and `checkout.session.completed` events. If you enter the **signing secret** (`whsec_…`) on the card, `Stripe-Signature` is verified. Payments are added as notes on the company; for failed payments and ended subscriptions, a task is created for the owner. The company is found by a previously linked Stripe customer ID or by the customer's email; on a `checkout.session.completed` event, if no company exists, one is created as a prospect.

## Bookings: Calendly and Cal.com {#booking}

When a booking is made, a meeting is added to the calendar, and a person and a note are added to the company; when the booking is canceled, the meeting is canceled too. In Calendly, select the `invitee.created` / `invitee.canceled` events; in Cal.com, select `BOOKING_CREATED`, `BOOKING_RESCHEDULED`, and `BOOKING_CANCELLED`.

## Meeting notes {#meeting-notes}

Summaries from AI meeting-note tools (Fireflies, Fathom, tl;dv, Otter… directly or via Zapier) are added as notes on the attendees' companies; action items become tasks due in two days.

```json
{
  "id": "mtg_5521",
  "title": "Kuzey Plastik · haftalık",
  "summary": "Numune sonuçları olumlu, fiyat revizyonu istendi.",
  "attendees": [{ "email": "emre.yildiz@kuzeyplastik.com.tr", "name": "Emre Yıldız" }],
  "action_items": ["Revize fiyatı gönder", "Hat denemesi tarihini netleştir"],
  "url": "https://…"
}
```

## lemlist {#lemlist}

Campaign events (`emailsReplied`, `linkedinReplied`, `emailsInterested`, `meetingBooked`, `emailsNotInterested`, `emailsBounced`, `emailsUnsubscribed`, `emailsClicked`) are added as notes on the person's company; for reply, interest, and meeting events, a "follow up" task is created for the owner.

## Slack command {#slack}

In your Slack app, define a **Slash Command** (e.g. `/crm`) with the connection's URL as the request URL, and enter Slack's **Signing Secret** on the card. A user who types `/crm kuzey` gets the matching companies, people, and opportunities in a reply that only they can see.