İçeriğe geç
Geliştiriciler

Kulak API dokümantasyonu

Bahsedilmeleri, anahtar kelimeleri, alarmları ve webhook'ları kendi uygulamandan yönet. REST API her planda, deneme dahil, ek ücret olmadan açık.

Hızlı başlangıç

  1. 1Kulak'a kayıt ol ve bir proje oluştur; anahtar kelimelerini ekle.
  2. 2Panelde Geliştirici bölümünden bir API anahtarı oluştur. Anahtar yalnızca bir kez gösterilir, güvenli bir yerde sakla.
  3. 3Aşağıdaki istekle en acil bahsedilmeleri çek. Proje kimliğini panelin adres çubuğunda veya GET /projects yanıtında bulursun.
ilk-istek.sh
curl "https://kulak.app/api/v1/mentions?projectId=prj_123&minUrgency=4&limit=20" \
-H "Authorization: Bearer kl_live_xxxxxxxxxxxxxxxx"

Kimlik doğrulama

Her istekte Authorization: Bearer kl_live_... başlığını gönder. Anahtarlar sunucuda yalnızca özetlenmiş (hash) olarak saklanır; kaybedersen yenisini oluşturup eskisini iptal et.

Anahtarlar kapsam (scope) ile sınırlandırılır. :write kapsamı aynı kaynağın :read iznini de içerir. Bir anahtarı tek bir projeyle de sınırlayabilirsin; bu durumda projectId parametresi opsiyoneldir.

Erişimin olmayan ya da var olmayan kaynaklar aynı şekilde 404 döner; böylece başka hesaplara ait kimlikler tahmin edilemez.

Kapsamlar
KapsamAçıklama
projects:readProjeleri okuma
projects:writeProjeleri yönetme
keywords:readAnahtar kelimeleri okuma
keywords:writeAnahtar kelimeleri yönetme
mentions:readMention'ları okuma
mentions:writeMention durumlarını güncelleme
alerts:readAlarmları okuma
alerts:writeAlarmları yönetme
webhooks:readWebhook'ları okuma
webhooks:writeWebhook'ları yönetme
usage:readKullanım ve kota bilgisi
account:readHesap bilgisi

REST kuralları

Temel adres https://kulak.app/api/v1. İstek ve yanıt gövdeleri JSON'dur; gövde en fazla 64 KB olabilir.

Her yanıt aynı zarfı kullanır. Başarılı yanıtlar data ve meta, hatalar error alanı taşır. Her yanıtta x-request-id başlığı ve meta.requestId bulunur; destek taleplerinde bu kimliği paylaş.

200 OK
{
"data": {
"id": "mnt_8f2k",
"source": "x",
"sentiment": "olumsuz",
"urgency": 5
},
"meta": {
"requestId": "req_3b1c9e",
"idempotencyReplayed": false
}
}
422 Unprocessable Entity
{
"error": {
"code": "validation_error",
"message": "Gönderilen veri geçersiz.",
"requestId": "req_3b1c9e",
"issues": [
{
"path": "term",
"message": "En az 2 karakter olmalı."
}
]
}
}

Hatalar

Hata kodu makine tarafından okunur ve sabittir; mesaj insan içindir ve değişebilir. İstemcinde her zaman error.code alanına göre dallan.

Hatalar
KodHTTPAnlamı
bad_request400İstek biçimi hatalı (ör. geçersiz tarih aralığı).
validation_error422Gövde veya parametreler doğrulamadan geçmedi; ayrıntı issues içinde.
unauthorized401API anahtarı eksik, geçersiz ya da iptal edilmiş.
forbidden403Anahtarın bu işlem için gereken kapsamı yok.
not_found404Kaynak yok ya da erişimin yok.
conflict409Kaynak durumu isteği karşılamıyor (ör. aynı anahtar kelime zaten var).
payload_too_large413Gövde 64 KB sınırını aşıyor.
rate_limited429Dakikalık istek sınırı aşıldı; Retry-After kadar bekle.
quota_exceeded402Plan limiti doldu (ör. anahtar kelime sayısı).
unavailable503Hizmet geçici olarak kullanılamıyor; üstel bekleme ile yeniden dene.
internal500Beklenmeyen hata. requestId ile bize yaz.

Idempotency

Yazma isteklerinde (POST, PATCH, DELETE) Idempotency-Key başlığı gönderebilirsin (en fazla 255 karakter). Aynı anahtarla tekrarlanan istek 24 saat boyunca ilk yanıtı döndürür ve meta.idempotencyReplayed alanı true olur.

Ağ hatasından sonra yeniden denerken aynı anahtarı kullan; çift kayıt oluşmaz. Her yeni işlem için yeni bir anahtar (ör. UUID) üret.

anahtar-kelime-ekle.sh
curl -X POST "https://kulak.app/api/v1/keywords" \
-H "Authorization: Bearer kl_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7d0e2c1a-4f5b-4a51-9d0c-2a4f0e6b1c11" \
-d '{"projectId":"prj_123","term":"Tencere","type":"brand"}'

Sayfalama

Liste uç noktaları cursor tabanlıdır: ?limit= (varsayılan 25, en fazla 100) ve ?cursor=. Sonraki sayfa için yanıttaki meta.nextCursor değerini gönder; değer null ise son sayfadasın.

Cursor'lar opaktır; içeriğini ayrıştırma ya da elle üretme.

Rate limit

Her API anahtarı dakikada 120 istek yapabilir. Sınır aşıldığında 429 rate_limited ve saniye cinsinden Retry-After başlığı döner.

Toplu okumalarda en büyük sayfa boyutunu kullan, yeni veriyi sürekli sorgulamak yerine webhook'lara abone ol.

Webhook'lar

Panelden bir endpoint ekle ve dinlemek istediğin olayları seç. Kulak her olayı imzalı bir POST isteğiyle gönderir. Endpoint'in 2xx dönmelidir; aksi durumda teslimat yeniden denenir.

İstek zaman aşımı 10 saniyedir, yönlendirmeler takip edilmez. Başarısız teslimatlar üstel beklemeyle en fazla 8 kez denenir; art arda 20 başarısızlıktan sonra endpoint otomatik devre dışı kalır. Teslimat geçmişini panelden görebilir, tek tıkla yeniden gönderebilirsin.

Aynı olay birden fazla kez ulaşabilir; webhook-id başlığını saklayarak tekrarları ayıkla.

Başlıklar
BaşlıklarAçıklama
webhook-idOlayın benzersiz kimliği (tekrarları ayıklamak için).
webhook-timestampGönderim zamanı, Unix saniyesi.
webhook-signaturev1,<base64 imza>; secret rotasyonunda boşlukla ayrılmış birden çok imza olabilir.

Olaylar

  • mention.created
  • mention.updated
  • mention.status_changed
  • mention.marked_irrelevant
  • keyword.created
  • keyword.updated
  • keyword.deleted
  • keyword_group.created
  • keyword_group.updated
  • keyword_group.deleted
  • alert.created
  • alert.updated
  • alert.deleted
  • alert.delivered
  • project.created
  • project.updated
  • project.deleted
  • integration.connected
  • integration.disconnected
  • webhook.test
mention.created (kısaltılmış örnek)
{
"id": "evt_k2x9p1",
"type": "mention.created",
"timestamp": "2026-09-29T08:41:12.000Z",
"projectId": "prj_123",
"data": {
"id": "mnt_8f2k",
"source": "x",
"url": "https://x.com/...",
"text": "Tencere uygulamasında ödeme adımında sürekli hata alıyorum...",
"category": "hata_bildirimi",
"sentiment": "olumsuz",
"urgency": 5
}
}

İmza doğrulama

İmzalar Standard Webhooks biçimindedir: HMAC-SHA256(anahtar, "{webhook-id}.{webhook-timestamp}.{ham gövde}") sonucunun base64 kodlaması. Anahtar, whsec_ önekinden sonraki base64 değerin çözülmüş byte'larıdır.

Doğrulamayı JSON'u ayrıştırmadan önce, ham gövde üzerinde yap. Zaman damgası 5 dakikadan eskiyse isteği reddet (tekrar saldırılarına karşı) ve karşılaştırmada sabit zamanlı fonksiyon kullan.

verify-webhook.mjs
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 300;
/** rawBody: ayrıştırılmamış istek gövdesi (string). */
export function verifyKulakWebhook(secret, headers, rawBody) {
const id = headers["webhook-id"];
const ts = headers["webhook-timestamp"];
const sigHeader = headers["webhook-signature"];
if (!id || !ts || !sigHeader) return false;
if (Math.abs(Date.now() / 1000 - Number(ts)) > TOLERANCE_SECONDS) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest();
return sigHeader.split(" ").some((part) => {
const [version, sig] = part.split(",", 2);
if (version !== "v1" || !sig) return false;
const given = Buffer.from(sig, "base64");
return given.length === expected.length && timingSafeEqual(given, expected);
});
}

Uç nokta referansı

Bu liste uygulamanın ürettiği OpenAPI belgesinden otomatik oluşturulur; her zaman API ile birebir aynıdır.

Projeler

  • GET/api/v1/projectsProjeleri listele
    Kapsam: projects:readBaşarı: 200
  • POST/api/v1/projectsProje oluştur
    Kapsam: projects:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    namezorunlustring
    descriptionopsiyonelstring | null
    timezoneopsiyonelstring
    languageopsiyoneltr | en
  • GET/api/v1/projects/{id}Proje ayrıntısı
    Kapsam: projects:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/projects/{id}Proje güncelle
    Kapsam: projects:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    nameopsiyonelstring
    descriptionopsiyonelstring | null
    timezoneopsiyonelstring
    languageopsiyoneltr | en
  • DELETE/api/v1/projects/{id}Proje sil
    Kapsam: projects:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • GET/api/v1/projects/{id}/membersÜyeler ve davetler
    Kapsam: projects:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • POST/api/v1/projects/{id}/membersÜye davet et
    Kapsam: projects:writeBaşarı: 201Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    emailzorunlustring
    roleopsiyoneladmin | member | viewer

Anahtar kelimeler

  • GET/api/v1/keywordsKeyword'leri listele
    Kapsam: keywords:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
  • POST/api/v1/keywordsKeyword oluştur (plan limiti uygulanır)
    Kapsam: keywords:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    termzorunlustring
    aliasesopsiyonelstring[]
    excludeTermsopsiyonelstring[]
    matchModeopsiyonelphrase | exact | any_word
    languageopsiyoneltr | en | any
    sourcesopsiyonelx | reddit | youtube | linkedin[]
    typeopsiyonelbrand | product | competitor | person | topic
    groupIdopsiyonelstring | null
    activeopsiyonelboolean
    projectIdzorunlustringProje kimliği
  • GET/api/v1/keywords/{id}Keyword ayrıntısı
    Kapsam: keywords:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/keywords/{id}Keyword güncelle / duraklat (active)
    Kapsam: keywords:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    termopsiyonelstring
    aliasesopsiyonelstring[]
    excludeTermsopsiyonelstring[]
    matchModeopsiyonelphrase | exact | any_word
    languageopsiyoneltr | en | any
    sourcesopsiyonelx | reddit | youtube | linkedin[]
    typeopsiyonelbrand | product | competitor | person | topic
    groupIdopsiyonelstring | null
    activeopsiyonelboolean
  • DELETE/api/v1/keywords/{id}Keyword sil
    Kapsam: keywords:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • GET/api/v1/keyword-groupsGrupları listele
    Kapsam: keywords:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
  • POST/api/v1/keyword-groupsGrup oluştur
    Kapsam: keywords:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    namezorunlustring
    coloropsiyonelstring
    projectIdzorunlustringProje kimliği
  • GET/api/v1/keyword-groups/{id}Grup ayrıntısı
    Kapsam: keywords:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/keyword-groups/{id}Grup güncelle
    Kapsam: keywords:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    nameopsiyonelstring
    coloropsiyonelstring
  • DELETE/api/v1/keyword-groups/{id}Grup sil
    Kapsam: keywords:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

Mention'lar

  • GET/api/v1/mentionsMention akışı (filtreli, cursor sayfalı)
    Kapsam: mentions:readBaşarı: 200Cursor sayfalı

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
    sourcesopsiyonelstring · queryKaynaklar
    categoriesopsiyonelstring · queryKategori anahtarları (virgüllü)
    sentimentsopsiyonelstring · queryDuygular
    minUrgencyopsiyonelinteger · queryEn düşük aciliyet (1-5)
    statusesopsiyonelstring · queryDurumlar
    keywordIdsopsiyonelstring · queryKeyword kimlikleri (virgüllü)
    groupIdsopsiyonelstring · queryKeyword grup kimlikleri (virgüllü)
    fromopsiyonelstring · queryBaşlangıç (ISO 8601)
    toopsiyonelstring · queryBitiş (ISO 8601)
    datePresetopsiyoneltoday | 7d | 30d | this_month · queryHazır aralık
    qopsiyonelstring · queryMetin araması (tam kelime + içerir)
    isIrrelevantopsiyonelboolean · querytrue: yalnızca alakasızlar (varsayılan: gizli)
    hasFlagsopsiyonelstring · queryOlasılığı >= 0.5 olan bayraklar
    sortopsiyonelpublishedAt | urgency · querySıralama
    cursoropsiyonelstring · queryÖnceki yanıttaki meta.nextCursor
    limitopsiyonelinteger · querySayfa boyutu (varsayılan 25, en fazla 100)
  • GET/api/v1/mentions/{id}Mention ayrıntısı (tespit özeti + notlar; maliyet/model/ham tespit içermez)
    Kapsam: mentions:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/mentions/{id}Durum güncelle
    Kapsam: mentions:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    statuszorunlunew | reviewed | actioned | archived
  • POST/api/v1/mentions/{id}/irrelevantAlakasız işaretle / geri al
    Kapsam: mentions:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    irrelevantopsiyonelboolean
    reasonopsiyonelstring

Analiz

  • GET/api/v1/analytics/mentionsMention analizi (zaman serisi, dağılımlar, ses payı)
    Kapsam: mentions:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
    fromopsiyonelstring · queryBaşlangıç (ISO)
    toopsiyonelstring · queryBitiş (ISO)
    granularityopsiyonelhour | day | week | month · queryKova
    sourcesopsiyonelstring · queryKaynaklar
    keywordIdsopsiyonelstring · queryKeyword kimlikleri (virgüllü)

Kategoriler

  • GET/api/v1/categoriesKategorileri listele
    Kapsam: projects:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
  • POST/api/v1/categoriesKategori oluştur
    Kapsam: projects:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    keyopsiyonelstring
    namezorunlustring
    descriptionzorunlustring
    coloropsiyonelstring
    iconopsiyonelstring
    activeopsiyonelboolean
    projectIdzorunlustringProje kimliği
  • GET/api/v1/categories/{id}Kategori ayrıntısı
    Kapsam: projects:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/categories/{id}Kategori güncelle
    Kapsam: projects:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    nameopsiyonelstring
    descriptionopsiyonelstring
    coloropsiyonelstring
    iconopsiyonelstring
    activeopsiyonelboolean
  • DELETE/api/v1/categories/{id}Kategori sil (sistem kategorileri hariç)
    Kapsam: projects:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

Alarmlar

  • GET/api/v1/alertsAlarmları listele
    Kapsam: alerts:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
  • POST/api/v1/alertsAlarm oluştur
    Kapsam: alerts:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    namezorunlustring
    channelzorunluemail | webhook
    targetEmailsopsiyonelstring[]
    targetWebhookIdopsiyonelstring | null
    conditionsopsiyonelobject
    frequencyopsiyonelinstant | hourly | daily
    activeopsiyonelboolean
    projectIdzorunlustring
  • GET/api/v1/alerts/{id}Alarm ayrıntısı
    Kapsam: alerts:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/alerts/{id}Alarm güncelle
    Kapsam: alerts:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    nameopsiyonelstring
    channelopsiyonelemail | webhook
    targetEmailsopsiyonelstring[]
    targetWebhookIdopsiyonelstring | null
    conditionsopsiyonelobject
    frequencyopsiyonelinstant | hourly | daily
    activeopsiyonelboolean
  • DELETE/api/v1/alerts/{id}Alarm sil
    Kapsam: alerts:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

Kayıtlı görünümler

  • GET/api/v1/saved-viewsGörünümleri listele
    Kapsam: mentions:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
  • POST/api/v1/saved-viewsGörünüm oluştur
    Kapsam: mentions:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    namezorunlustring
    filterszorunluobject
    isSharedopsiyonelboolean
    projectIdzorunlustringProje kimliği
  • GET/api/v1/saved-views/{id}Görünüm ayrıntısı
    Kapsam: mentions:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/saved-views/{id}Görünüm güncelle
    Kapsam: mentions:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    nameopsiyonelstring
    filtersopsiyonelobject
    isSharedopsiyonelboolean
    sortOrderopsiyonelinteger
  • DELETE/api/v1/saved-views/{id}Görünüm sil
    Kapsam: mentions:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

Webhook'lar

  • GET/api/v1/webhooksWebhook'ları listele
    Kapsam: webhooks:readBaşarı: 200

    Parametreler

    projectIdzorunlustring · queryProje kimliği (projeye kısıtlı API anahtarında opsiyonel)
  • POST/api/v1/webhooksWebhook oluştur (secret yalnızca bu yanıtta)
    Kapsam: webhooks:writeBaşarı: 201Idempotency-Key destekler

    Gövde alanları

    urlzorunlustring
    descriptionopsiyonelstring | null
    eventszorunlumention.created | mention.updated | mention.status_changed | mention.marked_irrelevant | keyword.created | keyword.updated | keyword.deleted | keyword_group.created | keyword_group.updated | keyword_group.deleted | alert.created | alert.updated | alert.deleted | alert.delivered | project.created | project.updated | project.deleted | integration.connected | integration.disconnected | webhook.test[]
    activeopsiyonelboolean
    projectIdzorunlustringProje kimliği
  • GET/api/v1/webhooks/{id}Webhook ayrıntısı
    Kapsam: webhooks:readBaşarı: 200

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • PATCH/api/v1/webhooks/{id}Webhook güncelle
    Kapsam: webhooks:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği

    Gövde alanları

    urlopsiyonelstring
    descriptionopsiyonelstring | null
    eventsopsiyonelmention.created | mention.updated | mention.status_changed | mention.marked_irrelevant | keyword.created | keyword.updated | keyword.deleted | keyword_group.created | keyword_group.updated | keyword_group.deleted | alert.created | alert.updated | alert.deleted | alert.delivered | project.created | project.updated | project.deleted | integration.connected | integration.disconnected | webhook.test[]
    activeopsiyonelboolean
  • DELETE/api/v1/webhooks/{id}Webhook sil
    Kapsam: webhooks:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • POST/api/v1/webhooks/{id}/testTest olayı gönder (senkron sonuç)
    Kapsam: webhooks:writeBaşarı: 200Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği
  • GET/api/v1/webhooks/{id}/deliveriesTeslimat geçmişi
    Kapsam: webhooks:readBaşarı: 200Cursor sayfalı

    Parametreler

    idzorunlustring · pathKaynak kimliği
    cursoropsiyonelstring · queryÖnceki yanıttaki meta.nextCursor
    limitopsiyonelinteger · querySayfa boyutu (varsayılan 25, en fazla 100)
  • POST/api/v1/webhooks/{id}/deliveries/{deliveryId}/replayTeslimatı yeniden gönder
    Kapsam: webhooks:writeBaşarı: 202Idempotency-Key destekler

    Parametreler

    idzorunlustring · pathKaynak kimliği
    deliveryIdzorunlustring · pathTeslimat kimliği

Hesap

  • GET/api/v1/usagePlan ve kota kullanımı
    Kapsam: usage:readBaşarı: 200

    Parametreler

    projectIdopsiyonelstring · queryVerilirse proje sahibinin kotası
  • GET/api/v1/accountHesap bilgisi
    Kapsam: account:readBaşarı: 200

Anahtarını oluştur, ilk isteğini at

API ve webhook her planda, deneme dahil. Kredi kartı gerekmez.