İçeriğe geç

API Dokümantasyonu

Planlanan genel REST API'nin taslak sözleşmesi

v2.0 Yayında
Bu API yayında.

Aşağıdaki uçlar bugün çalışan sözleşmedir. API Enterprise planına dahildir ve anahtarı panelden siz üretirsiniz: Ayarlar → API anahtarları. Sunucudan sunucuya kullanılır; tarayıcıdan çağrılamaz.

Panelden anahtar oluşturun

Kapsam: Bu API okur ve mesaj gönderir. Bot oluşturma ve silme bilerek yoktur; ikisi de plan bot limitine ve faturanıza dokunur.

Yayında

🚀 Başlangıç

Sunucudan sunucuya bir REST API. İstekler HTTPS üzerinden yapılır, gövde ve yanıt JSON'dur. Enterprise planına dahildir; anahtarı panelden siz üretirsiniz.

Base URL

https://idgugvpofiqyaupkwtbs.supabase.co/functions/v1/public-api/v2

Adres bugün budur. İleride özel bir alan adı eklenirse yollar ve sözleşme aynı kalacak; yalnızca kök adres değişecektir. Adresi kodunuzda tek bir yerde tutun.

⚠️ Tarayıcıdan çağrılamaz: Bu uç hiçbir CORS başlığı döndürmez, bu yüzden tarayıcı içinden yapılan bir çağrı okunamaz. Bu bilerek böyle: anahtar bir sırdır ve sayfa koduna konan sır herkesindir. Çağrıyı kendi sunucunuzdan yapın.

Hızlı Başlangıç

cURL
curl "https://idgugvpofiqyaupkwtbs.supabase.co/functions/v1/public-api/v2/chatbots" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
Yayında

🔐 Kimlik Doğrulama

Her istek bir Bearer anahtarı taşır. Anahtarı panelden alırsınız: Ayarlar → API anahtarları → Anahtar oluştur. Anahtar hesabınızın tamamına erişir; botlarınızı ve konuşmalarınızı okur, mesaj gönderirken aylık mesaj hakkınızı harcar.

Authorization Header
Authorization: Bearer sk_live_YOUR_KEY
⚠️ Anahtar bir kez gösterilir: Sunucuda anahtarın kendisi değil yalnızca SHA-256 özeti saklanır, bu yüzden hiçbir liste onu bir daha döndüremez. Ürettiğiniz anda kaydedin. Kaybederseniz panelden iptal edip yenisini üretin; iptal edilen anahtar o an çalışmayı bırakır.
Plan ve sıra: Kapılar şu sırayla işler: anahtar doğrulanır, sonra planın REST API hakkı, sonra hız sınırı, en sonda yönlendirme. Bunun iki görünür sonucu var: geçerli bir anahtarla var olmayan bir yola giderseniz 404 alırsınız ve bu bir hız sınırı yuvası harcar; geçersiz bir anahtarla ise yol ne olursa olsun 401 alırsınız, asla 404 değil.
⚠️ Güvenlik Uyarısı: API anahtarlarınızı asla public repository'lerde paylaşmayın. Environment variables kullanın.
Yayında

🤖 Chatbots

Bu API bot oluşturmaz ve silmez: Bot oluşturma ve silme bilerek dışarıda bırakıldı; ikisi de plan bot limitine ve faturanıza dokunuyor. Botları panelden ya da kurulum sihirbazından yönetin. Bu API okur ve mesaj gönderir.
GET /v2/chatbots

Hesabınızdaki botları listeler. Yeniden eskiye doğru sıralanır. Sorgu parametreleri: limit, cursor.

Response

200
{
  "success": true,
  "data": [
    {
      "id": "6f1c9a52-...",
      "name": "Destek Botu",
      "description": null,
      "model": "flash",
      "active": true,
      "messages_used": 1240,
      "created_at": "2026-01-15T10:30:00Z",
      "updated_at": "2026-09-02T08:11:00Z"
    }
  ],
  "pagination": {
    "limit": 25,
    "returned": 1,
    "total": 1,
    "has_more": false,
    "next_cursor": null
  }
}
GET /v2/chatbots/{id}

Tek bir botu döndürür. Alanlar listedekiyle aynıdır ve yanıt data içinde tek nesnedir. Hesabınıza ait olmayan bir kimlik 404 chatbot_not_found döner.

Yayında

💬 Messages

POST /v2/messages

Bota bir mesaj gönderir ve yanıtı döndürür. Kabul edilen gövde alanları tam olarak dörttür.

Request Body

request
{
  "chatbot_id": "6f1c9a52-...",
  "message": "Merhaba, kargom nerede?",
  "user_id": "musteri-4821",
  "language": "tr"
}

chatbot_id ve message zorunludur; message en fazla 4000 karakter olabilir. user_id ve language isteğe bağlıdır. language gerçekten uygulanır: verildiğinde otomatik dil algılamanın önüne geçer.

Response

200
{
  "success": true,
  "data": {
    "chatbot_id": "6f1c9a52-...",
    "user_id": "musteri-4821",
    "session_id": "api:musteri-4821",
    "channel": "api",
    "message": "Merhaba, kargom nerede?",
    "reply": "Sipariş numaranızı paylaşırsanız hemen bakayım.",
    "created_at": "2026-09-02T14:30:00.000Z"
  }
}
⚠️ user_id vermezseniz sunucu üretir: Bu alanı boş bırakırsanız sunucu rastgele bir kimlik üretir ve yanıtta size döndürür. Onu saklamazsanız aynı konuşmayı sürdüremezsiniz: bir sonraki çağrı yeni bir konuşma açar. Aynı son kullanıcı için her zaman aynı user_id'yi gönderin.
⚠️ Bu uç mesaj hakkınızı harcar: Buradan gönderilen her mesaj, WhatsApp ya da web widget'ından gelen bir mesajla tamamen aynı kotadan düşer. Hak bittiğinde uç 402 message_quota_exceeded döner.
Hata gerçek hatadır: Kanal tarafında model yanıt veremediğinde ziyaretçiye nazik bir yedek cümle gösterilir. Bu uçta öyle olmaz: kota dolduğunda ya da model yanıt veremediğinde HTTP hata kodu ve makine okunur bir hata kodu alırsınız, başarılı görünen bir metin değil.
Yayında

🗂️ Conversations

GET /v2/conversations

Botlarınızın konuşmalarını listeler; en son mesaj alanına göre yeniden eskiye sıralanır. Sorgu parametreleri: limit, cursor, chatbot_id ve channel. Liste mesaj gövdelerini taşımaz — bir konuşmanın mesajları için detay ucunu kullanın.

Response

200
{
  "success": true,
  "data": [
    {
      "id": "0b7d41e8-...",
      "chatbot_id": "6f1c9a52-...",
      "channel": "whatsapp",
      "user_id": "905xxxxxxxxx",
      "session_id": "whatsapp:905xxxxxxxxx",
      "visitor_name": null,
      "visitor_email": null,
      "last_message_at": "2026-09-02T13:58:00",
      "created_at": "2026-08-30T09:12:00",
      "updated_at": "2026-09-02T13:58:00"
    }
  ],
  "pagination": { "limit": 25, "returned": 1, "total": 1, "has_more": false, "next_cursor": null }
}

Buradaki user_id, kanalın ucundaki kişidir — sizin hesap kimliğiniz değil. POST /v2/messages ile gönderdiğiniz user_id ile aynı alandır, o yüzden API'den açtığınız konuşmaları bu alandan eşleyebilirsiniz.

GET /v2/conversations/{id}

Tek bir konuşmayı, mesaj geçmişiyle döndürür. Liste alanlarına ek olarak message_count, messages ve messages_truncated taşır.

message_limit parametresi kaç mesaj döneceğini belirler: varsayılan 100, en fazla 500 ve her zaman EN YENİ mesajlar. Geçmişin tamamı dönmediyse messages_truncated true olur; message_count gerçek toplamı verir.

Başka bir hesabın kaydı 404 döner: Size ait olmayan bir chatbot_id ya da konuşma kimliği 403 değil 404 alır. 403 "bu kimlik var ama senin değil" bilgisini sızdırırdı; öğrenmeniz gereken tek şey o kaydın sizin hesabınızda bulunmadığıdır.
Yayında

📊 Analytics

GET /v2/analytics

Hesabın kullanım özeti. Tek sorgu parametresi days: varsayılan 30, en fazla 90. Yanıt üç bloktan oluşur: account, chatbots ve usage.

Response

200
{
  "success": true,
  "data": {
    "account": {
      "plan": "enterprise",
      "plan_version": 2,
      "subscription_status": "active",
      "messages_used": 4120,
      "messages_limit": 25000,
      "plan_message_limit": 20000,
      "plan_bot_limit": 20,
      "message_credits": 0
    },
    "chatbots": [
      {
        "id": "6f1c9a52-...",
        "name": "Destek Botu",
        "active": true,
        "messages_used_total": 1240,
        "messages_in_window": 310
      }
    ],
    "usage": {
      "window_days": 30,
      "from": "2026-08-03T14:30:00.000Z",
      "to": "2026-09-02T14:30:00.000Z",
      "covers_from": "2026-08-03T14:30:00.000Z",
      "truncated": false,
      "row_cap": 5000,
      "total_messages": 310,
      "total_tokens": 184320,
      "total_cost_usd": 1.284213,
      "by_day": [
        { "day": "2026-08-03", "messages": 12 }
      ]
    }
  }
}
⚠️ Toplamlar koşulsuz değildir: Toplamlar en fazla 5000 kullanım kaydı üzerinden hesaplanır (row_cap). Pencerede daha fazla kayıt varsa truncated true olur ve covers_from, toplamların GERÇEKTEN kapsadığı ilk anı verir. Bu durumda total_messages pencerenin tamamı değil, covers_from ile to arasıdır. Grafiği çizerken from değil covers_from kullanın.
İki limit alanı, iki ayrı şey: messages_limit hesap satırındaki değerdir ve elle ayarlanabilir; plan_message_limit ise planın sattığı sayıdır. Meşru olarak farklı olabilirler — örneğin destek ekibi hesabınıza ek hak tanımladıysa. Kalan hakkı hesaplarken messages_limit'i kullanın; planı anlatırken plan_message_limit'i.
Yayında

🔔 Giden webhook’lar

Bu bölüm yayında.

Sayfanın geri kalanı taslaktır; buradaki sözleşme bugün çalışan koddur. Business ve Enterprise planlarında kullanılabilir ve panelden, botun webhook ayarından kurulur — kurulum için çağırabileceğiniz bir REST ucu yoktur.

Botunuz bir talep ya da randevu yakaladığında, sizin belirlediğiniz https adresine imzalı bir JSON POST gönderiyoruz. Bağlantı tek yönlüdür: çağrıyı biz yaparız, siz bize çağrı yapmazsınız.

Gönderilen olaylar

  • request.created — bot bir talep yakaladıktan ve kayıt yazıldıktan sonra gönderilir.
  • appointment.created — bot bir randevu yakaladıktan ve kayıt yazıldıktan sonra gönderilir.
  • webhook.test — panelden test gönderimini siz başlattığınızda gönderilir. Abone olunacak bir olay değildir; gövdesi gerçek bir request.created ile aynı biçimdedir ve is_test alanı taşır.

Başlıklar

HTTP
POST https://example.com/synaptix
Content-Type: application/json
User-Agent: Synaptix-Webhooks/1.0
X-Synaptix-Event: request.created
X-Synaptix-Delivery: 6d0f1c2e-6a1f-4f4a-9a8d-2f7c5b1ea91b
X-Synaptix-Signature: sha256=<lowercase hex>

X-Synaptix-Delivery her deneme için yeniden üretilir ve gövdedeki delivery_id ile aynı değerdir. Tekilleştirme yapacaksanız bu değeri değil data.id alanını kullanın: aynı kayıt yeniden gönderilirse teslimat kimliği değişir, kayıt kimliği değişmez.

Webhook Payload

Zarf her olayda aynıdır; olaya göre değişen tek alan data’dır. Aşağıda bir request.created gövdesi var.

request.created
{
  "event": "request.created",
  "delivery_id": "6d0f1c2e-6a1f-4f4a-9a8d-2f7c5b1ea91b",
  "created_at": "2026-09-09T12:04:11.482Z",
  "bot_id": "1f0b6d5e-2a44-4c9f-8b21-9e6a2f3c7d10",
  "data": {
    "id": "9c1a7f22-4d63-4b0e-9d61-3a8f5c2b7e04",
    "request_type": "lead_collection",
    "status": "new",
    "message": "Fiyat listesi alabilir miyim?",
    "visitor_name": "Ada Yılmaz",
    "visitor_email": "ada@example.com",
    "visitor_phone": null,
    "source_page_host": "example.com",
    "created_at": "2026-09-09T12:04:11.101Z"
  }
}

appointment.created olayında zarf aynı kalır, data alanı ise şu alanları taşır:

appointment.created · data
{
  "id": "2b7d4f10-9c33-4a6e-8f52-71c0d9ab3e64",
  "request_id": "9c1a7f22-4d63-4b0e-9d61-3a8f5c2b7e04",
  "status": "pending",
  "message": "Cuma 14:30 için randevu",
  "visitor_name": "Ada Yılmaz",
  "visitor_email": "ada@example.com",
  "visitor_phone": "+90 555 000 00 00",
  "appointment_date": "2026-09-11",
  "appointment_time": "14:30",
  "appointment_at": "2026-09-11T11:30:00Z",
  "source_page_host": "example.com",
  "created_at": "2026-09-09T12:04:11.101Z"
}

İmzayı doğrulama

İmza şudur: HMAC-SHA256(imza anahtarınız, gövdenin ham baytları), küçük harfli hex. Başlıkta “sha256=” önekiyle taşınır. Aşağıdaki iki örnek doğrudan kendi ucunuza yapıştırılabilir.

Ham gövde şarttır. Gövdeyi ayrıştırıp yeniden JSON’a çevirirseniz anahtar sırası ve boşluklar değişir; imza o an tutmaz. Doğrulamayı ayrıştırmadan önce, aldığınız baytların üzerinde yapın.

Node.js (Express)
const crypto = require('crypto');
const express = require('express');
const app = express();

// express.raw: the signature covers the bytes we sent, so the handler
// must see the raw body and not a re-serialised object.
app.post('/synaptix', express.raw({ type: 'application/json' }), (req, res) => {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.SYNAPTIX_WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  const received = req.get('X-Synaptix-Signature') || '';
  const a = Buffer.from(expected, 'utf8');
  const b = Buffer.from(received, 'utf8');

  // timingSafeEqual throws when the lengths differ, so length is checked
  // first - and it is checked in constant time for equal-length input.
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('invalid signature');
  }

  const payload = JSON.parse(req.body.toString('utf8'));
  // payload.event, payload.delivery_id, payload.bot_id, payload.data
  res.sendStatus(200);
});
Python (Flask)
import hashlib
import hmac
import os
from flask import Flask, request

app = Flask(__name__)
SECRET = os.environ["SYNAPTIX_WEBHOOK_SECRET"].encode("utf-8")

@app.post("/synaptix")
def synaptix():
    raw = request.get_data()  # bytes, exactly as received
    expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    received = request.headers.get("X-Synaptix-Signature", "")

    # compare_digest is constant time and safe on unequal lengths.
    if not hmac.compare_digest(expected, received):
        return "invalid signature", 401

    payload = request.get_json()
    # payload["event"], payload["delivery_id"], payload["bot_id"], payload["data"]
    return "", 200
⚠️ Sabit zamanlı karşılaştırma: İki imzayı “===” ya da “==” ile karşılaştırmayın. Bu operatörler ilk farklı baytta durur; harcanan süre, denenen imzanın kaç baytının doğru olduğunu ele verir ve saldırgan doğru imzayı bayt bayt kurabilir. Node’da crypto.timingSafeEqual, Python’da hmac.compare_digest her karşılaştırmada aynı süreyi harcar; örneklerde bu yüzden onlar kullanılıyor.

Adres kuralları

Adres https olmalı ve genel internetten erişilebilen bir konağı göstermelidir. İsteği biz gönderdiğimiz için adres bizim ağ bağlamımızdan çözülür; bu yüzden localhost ve IPv6 karşılığı, 10.x, 172.16–31.x, 192.168.x, 169.254.x, IPv4’e eşlenmiş geri döngü adresleri, Synaptix’in kendi sunucuları ve içinde kullanıcı adı ya da parola taşıyan adresler kabul edilmez. Kendi ağınızın içindeki bir uca ulaşamayız.

Teslimat başarısız olursa

Uç noktanız 2xx dönmelidir. 3xx de başarısızlık sayılır: yönlendirmeyi takip etmiyoruz, çünkü https bir adresten özel bir adrese yapılan yönlendirme yukarıdaki konak kurallarını anlamsız kılardı. Her deneme sınırlı bir zaman aşımına tabidir; önce 2xx dönün, ağır işi sonra yapın. Başarılı da başarısız da her deneme kaydedilir ve panelde görünür; başarısız bir teslimat otomatik olarak tekrarlanmaz. Hiçbir durumda ziyaretçinin sohbeti bundan etkilenmez.

İmza anahtarı bir kez gösterilir

⚠️ Yalnızca bir kez: Anahtar, webhook’u kurduğunuz andaki yanıtta bir kez görünür; hiçbir listede, hiçbir durum sorgusunda bir daha dönmez ve panelin okuduğu görünümde zaten yer almaz. O anda kaydedin. Kaybederseniz panelden yeni bir anahtar üretebilirsiniz; yeni anahtar üretildiği anda eski anahtarla imzalanmış gövdeler doğrulanmaz, bu yüzden ucunuzu aynı anda güncelleyin.
Yayında

⚠️ Error Handling

Hata zarfı her uçta aynıdır ve DÜZDÜR — iç içe bir error nesnesi yoktur. error alanı makine tarafından okunacak kodu, message Türkçe ve message_en İngilizce açıklamayı taşır.

Error Response
{
  "success": false,
  "error": "message_too_long",
  "message": "Mesaj en fazla 4000 karakter olabilir.",
  "message_en": "A message may be at most 4000 characters.",
  "max_chars": 4000
}

Bazı hatalar zarfa ek üst düzey alanlar koyar; yukarıdaki max_chars bunlardan biridir. Diğerleri: required_plan / feature / plan (403), limit ve window_seconds (429), max_offset (400 cursor_out_of_range), chatbot_id (409), allow (405), method / path / supported_endpoints (404 unknown_endpoint), reason (402 ve 502).

Hata kodları

Kod Status Code Açıklama
missing_api_key401Authorization başlığı yok. Yanıt ayrıca WWW-Authenticate başlığı taşır.
invalid_api_key401Anahtar tanınmadı, biçimi hatalı ya da iptal edilmiş.
account_not_found401Anahtar geçerli ama bağlı olduğu hesap artık yok.
plan_required403Hesabın aktif bir planı yok. Gereken plan adı required_plan alanında döner.
plan_upgrade_required403Mevcut plan REST API'yi içermiyor. Gereken plan adı required_plan alanında döner.
rate_limit_exceeded429Dakikalık istek sınırı aşıldı. Retry-After başlığı kaç saniye bekleneceğini söyler.
unknown_endpoint404Böyle bir yol yok. Yanıt desteklenen uçların listesini de taşır.
method_not_allowed405Yol doğru, yöntem yanlış. Allow başlığı kabul edilen yöntemleri verir.
invalid_json400İstek gövdesi geçerli JSON değil.
missing_chatbot_id400chatbot_id alanı gönderilmedi.
missing_message400message alanı gönderilmedi ya da boş.
message_too_long400Mesaj 4000 karakter sınırını aştı.
invalid_cursor400Sayfalama imleci okunamadı. Yalnızca next_cursor değerini geri gönderin.
cursor_out_of_range40010.000 kayıt derinliğinin ötesine sayfalanamaz. Daha dar bir filtre kullanın.
chatbot_not_found404Bu kimlikte bir bot hesabınızda yok.
conversation_not_found404Bu kimlikte bir konuşma hesabınızda yok.
chatbot_inactive409Bot pasif durumda ve mesaj kabul etmiyor.
message_quota_exceeded402Aylık mesaj hakkı bitti ya da abonelik aktif değil.
assistant_unavailable502Yanıt üretilemedi. Tekrar denenebilir.
assistant_empty_reply502Model boş bir yanıt döndürdü. Mesaj gönderilmiş sayılmaz.
auth_backend_unavailable503Anahtar doğrulanamadı. İstek güvenli tarafta reddedildi; tekrar deneyin.
rate_limit_unavailable503Hız sınırı sayacı çalışmıyor. Sayamadığımız için geçirmiyoruz; tekrar deneyin.
service_unavailable503Servis geçici olarak yanıt veremiyor.
internal_error500Beklenmeyen bir hata. Sürerse destek ekibine bildirin.
Yayında

⏱️ Rate Limits

Sınır ANAHTAR BAŞINA dakikada 120 istektir. Pencere sabittir ve 60 saniyede bir sıfırlanır.

Hız sınırı, mesaj kotası değildir: Bu sınır kazaya karşıdır — döngüde kalmış ya da sızmış bir anahtarın hesabınızı ve paylaşılan altyapıyı dakikalar içinde tüketmesini engeller. Ne kadar mesaj gönderebileceğinizi belirleyen şey planınızın aylık mesaj hakkıdır, bu sayı değil.

Rate Limit Headers

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1789200000
Retry-After: 17

İlk üç başlık BAŞARILI yanıtlarda da gönderilir; görülemeyen bir sınır, ancak 429 yediğinizde öğrendiğiniz bir tuzaktır. Retry-After yalnızca 429 yanıtında bulunur.

⚠️ X-RateLimit-Reset bir süre değildir: Değer, pencerenin biteceği anın Unix zaman damgasıdır — SANİYE cinsinden, milisaniye değil. "Şu kadar saniye sonra" diye okursanız beklemeniz gereken süreyi yanlış hesaplarsınız. Kalan süre için o değerden şimdiki zamanı çıkarın; ya da 429 aldığınızda doğrudan Retry-After'ı kullanın.

Bugün kullanabileceğiniz yol

Yayımlanmış bir SDK paketimiz yok. Botunuzu sitenize bağlamak için kurulum sihirbazının verdiği gömme kodunu kullanın. WhatsApp, Instagram ve Messenger bağlantısı ise yakında açılacak; o zamana kadar panelden kurulamıyor.

Web widget

Kurulum sihirbazı size tek satırlık bir script etiketi verir; sayfanıza yapıştırmanız yeterlidir.

Kurulum rehberi

Meta kanalları

WhatsApp, Instagram ve Messenger tek bir bağlantıyla kurulacak ve kod yazmanız gerekmeyecek. Bu bağlantı yakında kullanıma açılacak.

Entegrasyon rehberi