Yapay zekâ destekli muhasebe API'si.
Tek REST API ile sesli komut, fotoğraf tarama, akıllı sohbet ve PDF raporlama. iOS, Android, Web, backend — her platformdan kullanırsın.
Giriş
Kilikon AI, KOBİ muhasebe yazılımı entegratörleri için tasarlanmış multi-tenant bir REST API'dir. Sesli komutla fatura kesim, kaşe/fatura/fiş OCR, finansal sohbet asistanı, çok turlu rapor üretimi gibi yapay zekâ özelliklerini tek endpoint kümesi üzerinden sunar.
Cloudflare Workers altyapısı + OpenAI (GPT-4o, Whisper, Vision) + ElevenLabs (TTS) arka uç. Senin platformunda (HBT iOS, Logo Android, Mikro Web) tek bir Bearer token ile çalışır.
Mevcut muhasebe yazılımının (e-Fatura, ön muhasebe, ERP) içine yapay zeka koymanın en kestirme yolu. OpenAI hesabı, prompt mühendisliği, KVKK aktarım sözleşmesi derdi sende değil — sen sadece HTTP istekleri atarsın. Türk KOBİ jargonuna (VKN, vergi dairesi, KDV dahil/hariç, e-Arşiv, GİB) eğitilmiş hazır endpoint'ler.
OpenAI hesabı açma, model güncelleme, prompt mühendisliği, rate limiting, KVKK aktarım yönetimi senin sorumluluğunda değil. Tek Bearer token, geri kalanı Kilikya halleder.
· HBT Function-Calling Pass-Through: Entegratör (Hızlı Bilişim) kendi son kullanıcısının session token'ını request body'sinde geçer. Kilikon AI, müşteri/cari bilgisine ihtiyaç duyduğunda OpenAI function calling ile o kullanıcının HBT API'sine doğrudan gider, canlı veri çeker. Token persist EDİLMEZ — sadece request scope'unda RAM'de tutulur, request bittiğinde discard edilir. Detay: HBT Context bölümü.
· Chain-of-Thought düşünme: Invoice AI artık cevap üretmeden önce iç düşünme adımı uygular (eksik alanlar, KDV durumu, belirsizlik) → daha az hata, daha az hallucination.
· Fuzzy müşteri/ürün matching: "Ahmet'e", "çukurovaya", "geçen seferki müşteri" gibi konuşma dili ifadeleri context'teki kayıtlarla 4 katmanlı eşleştirilir.
· Türkçe para birimi parsing: "12 bin", "on iki bin", "12K", "yarım milyon", "iki buçuk milyon" otomatik normalize edilir.
· Genişletilmiş müşteri şeması: Vergi dairesi, ilçe, şehir, telefon, e-posta — tümü artık fatura draft'ına dahil ve e-Fatura XML'ine yansır.
· KDV %20 default + dahil/hariç algılama: Türkiye 2024+ varsayılan KDV oranı, dahil/hariç ifade tanıma.
· Invoice modeli gpt-4o-mini: Slot-filling akışı ~3× daha hızlı (eski gpt-4o yerine), maliyet ~25× daha düşük.
· Yeni state: clarify: Belirsiz girdilerde AI options array'i ile seçenek sunar (örn. çoklu müşteri eşleşmesi).
Diyelim ki Hızlı Bilişim'in iOS app'ini yazıyorsun ve son kullanıcı zaten HBT'ye giriş yapmış — elinde session token var. Eskiden bu kullanıcının cari listesini Kilikya backend'inin tutması, replicate etmesi gerekirdi. Artık gerek yok: kullanıcı "1111111111 VKN'nin tam ünvanı nedir?" diye sorduğunda, sen HBT token'ını bizim isteğin context.hbt alanında geçirirsin. Kilikon AI tool çağrısıyla HBT'nin CariList'ine kullanıcının kendi yetki kapsamında gidip cevabı canlı çeker. Sen ortada cache, sync veya proxy yazmazsın — biz pass-through yaparız, sen sadece tek REST isteği atarsın.
Mimari
Senin Uygulaman Kilikon Worker OpenAI
───────────────── ────────────── ──────
iOS / Android / Web ─────▶ api.kilikon.tr ─────▶ GPT-4o
├ Tenant auth Whisper
├ Rate limit Vision
├ Usage tracking TTS
└ Hallucination filter
Desteklenen Platformlar
Foundation/URLSession yeterli. Minimal client örneği aşağıda.
OkHttp + Coroutines önerilen. Java ile de uyumlu.
Native fetch (Node 18+ veya tarayıcı). Bağımlılık yok.
requests veya httpx. Async destekli.
Aynı browser client.
Test ve hata ayıklama için.
Hızlı Başlangıç
5 dakika içinde ilk API çağrısını yapacaksın. Karmaşa yok, registry/account kurma yok.
"Hemen denemek istiyorum, dokümanı sonra okurum" diyen yazılımcı için. Token nasıl alınır, base URL ne, ilk istek nasıl atılır — sırasıyla 5 adım. Sonunda kendi terminalinden Kilikon'a bir cevap döndürmüş olursun; entegrasyonun kalanı bu örneği projeye uyarlamaktan ibaret.
-
Uygulamayı çalıştırmak için token'a ihtiyacın olacak.
İş Ortağı Formu'nu doldur, 24 saat içinde sana
kk_a1b2c3d4...formatında token e-posta ile iletilir. Sen formu doldurursun, biz token'ı üretip göndeririz — kalanını yazılımcın tek tuşla halleder. -
Base URL'i kullan.
Tüm istekler
https://api.kilikya.appüzerine yapılır. -
İlk çağrını yap.
Aşağıdaki örneği uygulamana kopyala. Token'ı yerleştir, çalıştır.
-
UI'yı entegre et.
Wireframe rehberini takip ederek Kilikon hub ekranını ve flow'ları yerleştir. Tasarım kararları HIG/Material 3 uyumlu.
-
KVKK onayını uygulamana ekle.
Son kullanıcıdan açık rıza al. Detay aşağıda.
Yazılımcının hesap açma, OpenAI key alma, API key yönetme derdi yok. İş ortağı formunu doldurursun → biz Kilikya admin panelinden tenant'ı yaratır, token'ı sana e-posta ile yollarız → yazılımcı kopyala-yapıştır → çalışıyor.
İlk API Çağrısı
curl https://api.kilikya.app/v1/chat \
-H "Authorization: Bearer kk_a1b2c3d4e5f67890abcdef1234567890" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Bu ay vergi durumum nasıl?"}
],
"context": "Bu ay gelir: ₺612.840, gider: ₺184.327"
}'struct ChatRequest: Encodable {
let messages: [Message]
let context: String
struct Message: Encodable { let role: String; let content: String }
}
let body = ChatRequest(
messages: [.init(role: "user", content: "Bu ay vergi durumum nasıl?")],
context: "Bu ay gelir: ₺612.840, gider: ₺184.327"
)
var req = URLRequest(url: URL(string: "https://api.kilikya.app/v1/chat")!)
req.httpMethod = "POST"
req.setValue("Bearer kk_a1b2...", forHTTPHeaderField: "Authorization")
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = try JSONEncoder().encode(body)
let (data, _) = try await URLSession.shared.data(for: req)
print(String(data: data, encoding: .utf8)!)val client = OkHttpClient()
val json = """
{
"messages": [{"role":"user","content":"Bu ay vergi durumum nasıl?"}],
"context": "Bu ay gelir: ₺612.840, gider: ₺184.327"
}
""".trimIndent()
val req = Request.Builder()
.url("https://api.kilikya.app/v1/chat")
.addHeader("Authorization", "Bearer kk_a1b2...")
.post(json.toRequestBody("application/json".toMediaType()))
.build()
val resp = client.newCall(req).execute()
println(resp.body!!.string())// pubspec.yaml: http: ^1.2.0
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<String> askKilikon(String question) async {
final resp = await http.post(
Uri.parse("https://api.kilikya.app/v1/chat"),
headers: {
"Authorization": "Bearer kk_a1b2c3d4e5f67890abcdef1234567890",
"Content-Type": "application/json",
},
body: jsonEncode({
"messages": [
{"role": "user", "content": question}
],
"context": "Bu ay gelir: ₺612.840, gider: ₺184.327",
}),
);
final data = jsonDecode(resp.body);
return data["text"] as String;
}
void main() async {
final reply = await askKilikon("Bu ay vergi durumum nasıl?");
print(reply);
}const resp = await fetch("https://api.kilikya.app/v1/chat", {
method: "POST",
headers: {
"Authorization": "Bearer kk_a1b2c3d4e5f67890abcdef1234567890",
"Content-Type": "application/json"
},
body: JSON.stringify({
messages: [{ role: "user", content: "Bu ay vergi durumum nasıl?" }],
context: "Bu ay gelir: ₺612.840, gider: ₺184.327"
})
});
const data = await resp.json();
console.log(data.text);import requests
resp = requests.post(
"https://api.kilikya.app/v1/chat",
headers={
"Authorization": "Bearer kk_a1b2c3d4e5f67890abcdef1234567890",
"Content-Type": "application/json",
},
json={
"messages": [{"role": "user", "content": "Bu ay vergi durumum nasıl?"}],
"context": "Bu ay gelir: ₺612.840, gider: ₺184.327",
},
)
print(resp.json()["text"])Beklenen Yanıt
{
"text": "Bu ayki net kârın 428 bin lira görünüyor. Geçen aya göre yüzde 8 büyüme var.\nKDV pozisyonun pozitif: 86 bin lira ödenmesi gereken. Geçici Vergi 2. dönem\nvadesi 17 Ağustos — tahmini 18.450 lira.",
"usage": {
"prompt_tokens": 142,
"completion_tokens": 89,
"total_tokens": 231
}
}Kimlik Doğrulama
Kilikon multi-tenant'tır. Her tenant = bir KOBİ son kullanıcısı (senin müşterin). Her tenant'ın benzersiz bir Bearer token'ı, günlük kullanım kotası ve bağımsız usage log'u vardır.
Her müşterinin kotasını ayırt etmek için. Sen entegratörsün — 100 KOBİ'ye hizmet veriyorsun. Her birinin ayrı kk_xxx token'ı oluyor; biri çok kullansa diğerini etkilemiyor. Kullanım faturalandırması da token bazında çıkıyor.
Token'ı asla kullanıcıya gösterme. Mobil app'te Keychain (iOS) veya EncryptedSharedPreferences (Android) ile sakla. Plain UserDefaults yetmez.
Header
Tüm /v1/* endpoint'lerine bu header ile gel (sadece /v1/health hariç):
Authorization: Bearer kk_9ce6d0686ad941648509a8cf7517b28cToken Yönetimi
Uygulamayı çalıştırmak için token'a ihtiyacın olacak. Bu yüzden doldurursun. Biz Kilikya admin panelinden tenant'ı yaratır, token'ı sana 24 saat içinde e-posta ile iletiriz. Yazılımcının admin panele girmesine gerek yok.
| Durum | Aksiyon |
|---|---|
| Token sızdı | Bize bildir → POST /admin/tenants/:id/rotate-token ile saniyeler içinde yenilenir |
| Müşteri sözleşmesi bitti | Suspend talep et → token 403 dönmeye başlar |
| Müşteri kalıcı ayrıldı | Delete talep et → tüm veri silinir |
401 ve 403 Yanıtları
// 401 — Token yok veya geçersiz
{"error": "Invalid token"}
// 403 — Tenant suspended
{"error": "Tenant suspended"}
Hata Yönetimi
Tüm hatalar JSON formatındadır, üst seviye error field'ı içerir.
Production'da hangi hatayı nasıl handle edeceğini bilmek için. 401 (token yok) ile 429 (kota doldu) farklı UX gerektirir — birinde kullanıcıyı login'e atarsın, diğerinde "Yarın saat 00:00'da resetleniyor" dersin. 5xx hatalarda retry yapılır, 4xx'te yapılmaz — bu tablo onu söyler.
| HTTP | Anlamı | Aksiyon |
|---|---|---|
| 200 | Başarılı | — |
| 400 | Geçersiz request body | Şemayı kontrol et |
| 401 | Token yok / geçersiz | Token'ı yeniden al |
| 403 | Tenant suspended | Admin'e başvur |
| 429 | Günlük kota doldu | resetAt'a kadar bekle |
| 500 | Worker hatası | Tekrar dene (backoff) |
| 502 | OpenAI yanıt vermiyor | Tekrar dene |
| 503 | Geçici unavailable | Tekrar dene |
Retry & Backoff
500/502/503 için exponential backoff kullan. 401/403/429 retry edilmez.
func retry<T>(_ work: () async throws -> T, maxAttempts: Int = 3) async throws -> T {
var lastError: Error?
for attempt in 0..<maxAttempts {
do {
return try await work()
} catch let urlError as URLError where [.notConnectedToInternet,
.timedOut].contains(urlError.code) {
lastError = urlError
} catch {
let nsErr = error as NSError
// 5xx retry, diğerleri throw
guard (500...599).contains(nsErr.code) else { throw error }
lastError = error
}
let delay: UInt64 = [500_000_000, 1_500_000_000, 4_000_000_000][min(attempt, 2)]
try await Task.sleep(nanoseconds: delay)
}
throw lastError!
}async function retry(fn, maxAttempts = 3) {
const delays = [500, 1500, 4000];
for (let i = 0; i < maxAttempts; i++) {
try {
return await fn();
} catch (err) {
const retryable = [500, 502, 503, 504].includes(err.status);
if (!retryable || i === maxAttempts - 1) throw err;
await new Promise(r => setTimeout(r, delays[i]));
}
}
}Hız Limitleri
Her tenant'ın günlük istek ve token limiti vardır. Limit aşılınca 429 dönülür.
Maliyeti kontrol altında tutmak için. AI çağrıları OpenAI'a token başına ücretlendirilir — limitsiz açarsan bir gecede 5 haneli fatura gelebilir. Plan başına günlük kotalar var, müşterin Pro plan ise 5.000 istek/gün hakkı var. UI'da kalan kotayı göstermek için /v1/usage'ı çağır.
| Plan | İstek/gün | Token/gün | Aylık tahmini |
|---|---|---|---|
| Free | 50 | 50K | $0 |
| Starter | 500 | 500K | ~$5 |
| Pro | 5.000 | 5M | ~$50 |
| Enterprise | Sınırsız | Sınırsız | Sözleşme |
429 Response
{
"error": "Daily request limit exceeded",
"limit": 500,
"used": 500,
"resetAt": "2026-06-05T00:00:00Z"
}
Reset UTC midnight'ta olur. UI'da progress bar göstermek için GET /v1/usage endpoint'ini kullan.
Endpoint Referansı
Invoice Converse
state: "ready" ile fatura taslağı döner. v2.1: Chain-of-thought düşünme + fuzzy müşteri/ürün matching + Türkçe para birimi parsing + 8 müşteri / 6 ürün alanı.Kullanıcı mikrofona "Ahmet'e 3 sandalye 12 bin lira kes" dediğinde, eksik bilgiyi (VKN, vergi dairesi, adres) tek tek soran AI asistanı. Slot-filling yapıyor — her cevapta state machine üzerinden ilerliyor. Mobil app'inde fatura ekranı açtırmadan, sesli/yazılı tek satırla fatura hazırlama. Çıktı doğrudan e-Fatura XML'ine uygun draft.
Slot Sırası (v2.1)
AI bilgileri şu sırayla toplar — kayıtlı müşteri context'te bulunursa adımları atlar:
customer_name— Müşteri ünvanı / adıcustomer_vkn— VKN veya TC kimlikcustomer_tax_office— Vergi dairesicustomer_address— Açık adrescustomer_district— İlçecustomer_city— İlcustomer_phone— Telefon (opsiyonel — kullanıcı "yok" diyebilir)customer_email— E-posta (opsiyonel)items[].name,quantity,unit_price,unit,kdv_rateprices_include_kdv— KDV dahil/hariç (büyük tutarda otomatik sorulur)
Request Body
null. Sonraki turlarda önceki cevabın sessionId'sini gönder.{ role: "user" | "assistant", content: string }.curl https://api.kilikya.app/v1/invoice/converse \
-H "Authorization: Bearer kk_a1b2..." \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role":"user","content":"Ahmet Yıldırım'\''a 5000 lira KDV dahil catering kes"}
],
"context": {
"company": {"name":"ABC A.Ş.","vkn":"4620553774"},
"customers": [{"id":"c1","name":"Ahmet Yıldırım","vkn":"1234567890"}],
"products": [{"name":"Catering paketi","price":2500,"unit":"paket"}]
}
}'struct ConverseRequest: Encodable {
let messages: [Msg]
let context: Context
struct Msg: Encodable { let role: String; let content: String }
struct Context: Encodable {
let company: Company
let customers: [Customer]
let products: [Product]
struct Company: Encodable { let name: String; let vkn: String }
struct Customer: Encodable { let id: String; let name: String; let vkn: String }
struct Product: Encodable { let name: String; let price: Double; let unit: String }
}
}
let body = ConverseRequest(
messages: [.init(role: "user", content: "Ahmet'e 5000 lira catering kes")],
context: .init(
company: .init(name: "ABC A.Ş.", vkn: "4620553774"),
customers: [.init(id: "c1", name: "Ahmet Yıldırım", vkn: "1234567890")],
products: [.init(name: "Catering paketi", price: 2500, unit: "paket")]
)
)
// POST to /v1/invoice/converse with Bearer headerconst resp = await fetch("https://api.kilikya.app/v1/invoice/converse", {
method: "POST",
headers: {
"Authorization": "Bearer kk_a1b2...",
"Content-Type": "application/json"
},
body: JSON.stringify({
messages: [
{ role: "user", content: "Ahmet'e 5000 lira catering kes" }
],
context: {
company: { name: "ABC A.Ş.", vkn: "4620553774" },
customers: [{ id: "c1", name: "Ahmet Yıldırım", vkn: "1234567890" }],
products: [{ name: "Catering paketi", price: 2500, unit: "paket" }]
}
})
});
const data = await resp.json();
if (data.response.state === "ready") {
console.log("Fatura taslağı:", data.response.draft);
} else if (data.response.state === "needs_info") {
console.log("AI soruyor:", data.response.say);
// Kullanıcıya göster, cevabı al, sessionId ile yeni tur başlat
}import requests
session_id = None
messages = [{"role": "user", "content": "Ahmet'e 5000 lira catering kes"}]
while True:
resp = requests.post(
"https://api.kilikya.app/v1/invoice/converse",
headers={"Authorization": "Bearer kk_a1b2..."},
json={
"sessionId": session_id,
"messages": messages,
"context": {
"company": {"name": "ABC A.Ş.", "vkn": "4620553774"},
"customers": [{"id": "c1", "name": "Ahmet Yıldırım", "vkn": "1234567890"}],
"products": [{"name": "Catering paketi", "price": 2500, "unit": "paket"}],
},
},
)
data = resp.json()
session_id = data["sessionId"]
r = data["response"]
if r["state"] == "ready":
print("Taslak:", r["draft"])
break
elif r["state"] == "needs_info":
print("AI:", r["say"])
user_reply = input("Sen: ")
messages.append({"role": "assistant", "content": r["say"]})
messages.append({"role": "user", "content": user_reply})Response States
Cevap her zaman state alanı ile gelir. Dört olası değer:
needs_info— Eksik alan var, AI tek soru sordu (field+say).clarify— Belirsizlik var, AIoptionsarray'i ile seçenek sunar (örn. iki "Mehmet" eşleşmesi).ready— Tüm alanlar dolu,drafthazır, kullanıcıya onay göstermeye uygun.error— Bir şeyler ters gitti (rare).
Response — needs_info
{
"sessionId": "abc-123",
"response": {
"state": "needs_info",
"field": "customer_vkn",
"say": "Ahmet Yıldırım için vergi kimlik numarasını söyler misin?",
"_thinking": "Müşteri context'te yok, VKN alanı boş. Bir sonraki adımda VKN sor."
}
}
Response — clarify (v2.1)
Birden fazla eşleşme bulunduğunda AI kullanıcıya seçenek sunar:
{
"sessionId": "abc-123",
"response": {
"state": "clarify",
"field": "customer_name",
"say": "Hangi Mehmet — Tekstil mi, İnşaat mı?",
"options": ["Mehmet Demir Tekstil", "Mehmet Yıldız İnşaat"],
"_thinking": "İki eşleşme var, açıkça sor."
}
}
Response — ready (v2.1 — genişletilmiş şema)
{
"sessionId": "abc-123",
"response": {
"state": "ready",
"say": "Ahşap sandalye 4 adet, toplam 14.400 lira oluyor. Keseyim mi?",
"draft": {
"direction": "income",
"customer_name": "Ahmet Yılmaz Ticaret",
"customer_vkn": "1234567890",
"customer_tax_office": "Kartal V.D.",
"customer_address": "İstanbul Pendik",
"customer_district": "Kartal",
"customer_city": "İstanbul",
"customer_email": "musteri@firma.com",
"customer_phone": "05321234567",
"customer_is_new": false,
"description": "Ahşap sandalye satışı",
"items": [
{"name": "Ahşap Sandalye", "qty": 4, "unit": "Adet",
"unit_price": 3000, "total": 12000, "kdv_rate": 20}
],
"subtotal": 12000,
"vat_rate": 20,
"vat_amount": 2400,
"total": 14400,
"prices_include_kdv": false,
"confidence": 0.92,
"_thinking": "Müşteri context'te var, VKN/adres dolu. KDV hariç varsay."
}
}
}
Yeni müşteri alanları: customer_tax_office, customer_district, customer_city, customer_email, customer_phone — tümü Invoice Commit ile HB / GİB e-Fatura XML'ine yansır.
Yeni ürün alanı: Her items[] satırı artık satır bazlı kdv_rate taşır (multi-rate fatura desteği).
Yeni flag: prices_include_kdv (boolean) — birim fiyatların KDV dahil mi hariç mi olduğunu belirtir.
Yeni debug alanı: _thinking — AI'nın chain-of-thought iç düşüncesi (kullanıcıya gösterilmez, prompt mühendisliği debug'u için).
1. İlk istekte sessionId: null ile başla.
2. AI state: "needs_info" veya "clarify" dönerse say'i kullanıcıya göster (UI veya TTS).
3. Kullanıcının cevabını messages'a ekle, aynı sessionId'yle yeni istek at.
4. state: "ready" görürsen draft'ı kullanıcıya önizleme olarak göster, onay sonra /v1/invoice/commit ile GİB'e ilet.
Context içinde HBT bilgilerini gönderme (v2.2)
Eğer entegratörünüz Hızlı Bilişim Teknolojileri (HBT) ise, request body'sinde aşağıdaki gibi context.hbt objesini geçirin. AI, kullanıcı VKN sorduğunda veya müşteri seçim ihtiyacı doğduğunda otomatik olarak HBT'nin CariList endpoint'ine kullanıcının kendi session token'ı ile gidip canlı veri çekecek. Bu hem /v1/invoice/converse hem /v1/chat için geçerlidir.
{
"messages": [
{ "role": "user", "content": "1111111111 VKN'nin tam ünvanı nedir?" }
],
"context": {
"hbt": {
"session_token": "eyJhbGc...",
"vkn": "4620553774",
"base_url": "https://econnecttest.hizliteknoloji.com.tr"
}
}
}
| Alan | Tip | Açıklama |
|---|---|---|
context.hbt.session_token |
string · zorunlu | HBT Login endpoint'inden dönen Token. Kullanıcının kendi yetki kapsamında HBT API'lerine çağrı için kullanılır. |
context.hbt.vkn |
string · opsiyonel | Kullanıcının firma VKN'si — fatura kesim akışlarında gönderici olarak kullanılır. |
context.hbt.base_url |
string · opsiyonel | HBT API base URL. Default: https://econnecttest.hizliteknoloji.com.tr (test). Production'da farklı olabilir. |
AI'nın kullanabileceği HBT tool'ları (v2.2)
Bu function'lar OpenAI function calling üzerinden AI'ya sunulur. Sen tool çağırmıyorsun — AI ihtiyaç duyduğunda kendi çağırıp sonuçla cevap üretiyor.
lookup_customer_by_vkn(vkn)— VKN veya TC kimlik numarasına göre tek müşteri döner.search_customers(query)— Ünvan veya ad ile arama (Türkçe karakter duyarsız, kısmi eşleşme, max 10 sonuç).list_recent_customers(limit)— Son kullanılan müşteriler listesi (default 10, max 50). Yeni fatura kesilirken hızlı seçim için.
Session expired (401): HBT token süresi dolmuşsa AI tool çağrısı içinde {"error":"session_expired"} alır ve sana "HBT oturumunuz dolmuş, tekrar giriş yapın" şeklinde yansıtır. Bu durumda kullanıcıyı HBT login'e yönlendirin ve yeni token ile aynı isteği tekrar atın.
HBT API hatası (5xx): AI state: "error" dönmek yerine en iyi tahmininle devam etmeye çalışır — tool çıktısı {"error":"hbt_api_error"} olarak iletilir.
Session token sadece request scope'unda RAM'de tutulur. Kilikon DB'sine, log'a, KV'ye, herhangi bir tenant analytics'ine ASLA yazılmaz. Request bittiği anda discard edilir. Sonraki request'te tekrar göndermeniz gerekir. Bu pass-through pattern, KVKK Madde 9 kapsamında "veri aktarımı"na girmez çünkü Kilikya token sahibinin kendi adına çağrı yapan teknik proxy olarak çalışır — veri Kilikya'da kalmaz.
Invoice Commit
draft'ı entegratörün arka uç servisi üzerinden GİB'e (Hızlı Bilişim, Logo, vb.) gönderir. Asenkron — UUID + invoice_number döner.
Onaylanmış faturayı GİB'e gönderir. Frontend'in state: "ready" aldığı draft'ı kullanıcıya gösterip "Onayla" dedikten sonra bu endpoint'i çağırırsın. Backend Hızlı Bilişim entegrasyonu ile UBL formatına çevirip GİB'e iletiyor. UUID + invoice_number döner, faturayı PDF olarak çekmek için bu UUID'yi kullanırsın.
Request Body
customer + lines[] + profile + notes.vkn, title, address, district, city, tax_office, email, phone — tümü XML'e yansır.product_name, quantity, unit_price, unit, kdv_rate. Birim Türkçe label kabul edilir (Adet, Saat, Kg, Lt, M2, Paket vb.) — backend UBL kodlarına çevirir.EARSIVFATURA (default, e-Arşiv) · TICARIFATURA · TEMELFATURA.curl https://api.kilikya.app/v1/invoice/commit \
-H "Authorization: Bearer kk_a1b2..." \
-H "Content-Type: application/json" \
-d '{
"email": "kullanici@firma.com",
"slots": {
"customer": {
"vkn": "1234567890",
"title": "Ahmet Yılmaz Ticaret",
"tax_office": "Kartal V.D.",
"address": "İstanbul Pendik",
"district": "Kartal",
"city": "İstanbul",
"email": "musteri@firma.com",
"phone": "05321234567"
},
"lines": [
{
"product_name": "Ahşap Sandalye",
"quantity": 4,
"unit_price": 3000,
"unit": "Adet",
"kdv_rate": 20
}
],
"profile": "EARSIVFATURA",
"notes": null
}
}'struct CommitRequest: Encodable {
let email: String
let slots: Slots
struct Slots: Encodable {
let customer: Customer
let lines: [Line]
let profile: String
struct Customer: Encodable {
let vkn, title, address, district, city: String
let taxOffice: String
let email, phone: String?
enum CodingKeys: String, CodingKey {
case vkn, title, address, district, city
case taxOffice = "tax_office"
case email, phone
}
}
struct Line: Encodable {
let productName: String
let quantity, unitPrice, kdvRate: Double
let unit: String
enum CodingKeys: String, CodingKey {
case productName = "product_name"
case quantity
case unitPrice = "unit_price"
case unit
case kdvRate = "kdv_rate"
}
}
}
}
// POST to /v1/invoice/commit, decode { uuid, invoice_number, status }const resp = await fetch("https://api.kilikya.app/v1/invoice/commit", {
method: "POST",
headers: { "Authorization": "Bearer kk_a1b2...", "Content-Type": "application/json" },
body: JSON.stringify({
email: "kullanici@firma.com",
slots: {
customer: {
vkn: "1234567890", title: "Ahmet Yılmaz Ticaret",
tax_office: "Kartal V.D.", address: "İstanbul Pendik",
district: "Kartal", city: "İstanbul",
email: "musteri@firma.com", phone: "05321234567"
},
lines: [{
product_name: "Ahşap Sandalye",
quantity: 4, unit_price: 3000, unit: "Adet", kdv_rate: 20
}],
profile: "EARSIVFATURA"
}
})
});
const { uuid, invoice_number, status } = await resp.json();Response
{
"uuid": "d6b80982-7811-45c3-8ef1-0a9f75f984fe",
"invoice_number": "KLY2026180544999",
"status": "OK",
"message": "Invoice sent successfully"
}
Dönen uuid ile entegratörün GET /document/file?uuid=...&format=PDF endpoint'ini çağırarak orijinal e-Arşiv / e-Fatura PDF'ini base64 olarak alabilirsin (HB tarafında GetDocumentFile proxy'lenir).
Chat
Genel finansal sohbet. Müşterin "Bu ay vergi durumum nasıl?" veya "KDV beyannamesini ne zaman vermem lazım?" gibi sorduğunda. GPT-4o-mini hızlı + ucuz — basit Q&A için yeterli, finansal jargonu Türkçe esnaf diliyle açıklıyor.
Request
{ hbt: { session_token, vkn?, base_url? } } şeklinde obje. HBT objesi geçilirse AI canlı cari listesine erişebilir, detay: HBT Context.curl https://api.kilikya.app/v1/chat \
-H "Authorization: Bearer kk_a1b2..." \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role":"user","content":"En riskli müşterim kim?"}],
"context": "Bekleyen tahsilat: Çukurova Un ₺22.500 (45 gün gecikme)"
}'const reply = await fetch("https://api.kilikya.app/v1/chat", {
method: "POST",
headers: { "Authorization": "Bearer kk_...", "Content-Type": "application/json" },
body: JSON.stringify({
messages: [{ role: "user", content: "En riskli müşterim kim?" }],
context: "Bekleyen tahsilat: Çukurova Un ₺22.500 (45 gün gecikme)"
})
}).then(r => r.json());
console.log(reply.text);# HBT pass-through: AI canlı cari listesinden VKN sorgular
curl https://api.kilikya.app/v1/chat \
-H "Authorization: Bearer kk_a1b2..." \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role":"user","content":"1111111111 VKN ünvanı nedir?"}],
"context": {
"hbt": {
"session_token": "eyJhbGc...",
"vkn": "4620553774",
"base_url": "https://econnecttest.hizliteknoloji.com.tr"
}
}
}'Report
Detaylı muhasebe raporu üretir. Müşterin "Son 6 ayın özetini çıkar" veya "KDV'm ne olacak yıl sonunda?" dediğinde markdown formatlı, başlıklı, tablolu rapor döner. GPT-4o (gelişmiş model) kullanır — bu yüzden Chat'ten yavaş ama çok daha derin analiz.
Request
Cevap text alanında ham markdown gelir. iOS'ta AttributedString(markdown:), Android'de Markwon, Web'de marked.js ile render et. PDF'e çevirmek için kendi PDF kütüphaneni kullan (örnek olarak iOS SDK'da hazır ReportPDFGenerator var).
Vision
Kullanıcı bir fatura/kaşe/fiş fotoğrafı çektiğinde, AI içinden alanları çıkarır: kim, kime, ne kadar, hangi tarih, KDV. OCR + bağlam anlama beraber. Kullanıcı fotoğrafı yükler, sen JSON olarak alır, otomatik fatura draft'ı oluşturursun. Mobile'da kamera entegrasyonu için ideal.
Request
data:image/... prefix opsiyonel.IMG=$(base64 -i kase.jpg | tr -d '\n')
curl https://api.kilikya.app/v1/vision \
-H "Authorization: Bearer kk_..." \
-H "Content-Type: application/json" \
-d "{\"imageBase64\":\"$IMG\"}"guard let jpeg = image.jpegData(compressionQuality: 0.7) else { return }
let base64 = jpeg.base64EncodedString()
var req = URLRequest(url: URL(string: "https://api.kilikya.app/v1/vision")!)
req.httpMethod = "POST"
req.setValue("Bearer kk_...", forHTTPHeaderField: "Authorization")
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = try JSONEncoder().encode(["imageBase64": base64])
let (data, _) = try await URLSession.shared.data(for: req)
let result = try JSONDecoder().decode(VisionResponse.self, from: data)
print(result.type, result.company ?? "")val base64 = Base64.encodeToString(jpegBytes, Base64.NO_WRAP)
val body = """{"imageBase64":"$base64"}""".toRequestBody("application/json".toMediaType())
val req = Request.Builder()
.url("https://api.kilikya.app/v1/vision")
.addHeader("Authorization", "Bearer kk_...")
.post(body)
.build()
val resp = client.newCall(req).execute()
val json = resp.body!!.string()
println(json)Response
{
"type": "stamp",
"company": "Kilikya Teknoloji A.Ş.",
"vkn": "4620553774",
"address": "Çukurova / Adana",
"phone": "+90 322 555 1234",
"taxOffice": "Ziyapaşa V.D.",
"invoiceNo": null,
"date": null,
"totalAmount": null,
"vatAmount": null,
"items": null,
"summary": "Adana'daki Kilikya Teknoloji şirketinin kaşesi.",
"suggestedActions": ["Müşteri olarak ekle", "Bu firmaya fatura kes"]
}
type şu değerlerden biri olur: stamp, invoice, receipt, idCard, other. Tip'e göre dolan alanlar değişir.
Transcribe (Whisper)
Sesli kaydı yazıya çevirir (Whisper). Mobile app'inde mikrofon → m4a kaydı → bu endpoint → text. Bonus: filtre var, sessizliklerde Whisper'ın ürettiği "altyazı m.k", "abone ol" tarzı bot kalıplarını temizliyor.
Sessiz ses kayıtlarında Whisper "Altyazı M.K." gibi YouTube-altyazı tarzı şeyler üretir. Bizim worker sunucu tarafında bunları yakalar ve text alanını boş döndürür. raw alanında ham çıktıyı görebilirsin (debug için).
Request (multipart)
| Field | Tip | Açıklama |
|---|---|---|
| file | binary | m4a, mp3, wav, ogg, webm — max 25 MB |
| model | string | whisper-1 |
| language | string | tr (Türkçe) |
| response_format | string | json |
| prompt | string | Türkçe muhasebe bias — önerilir, hallucination'ı azaltır |
curl https://api.kilikya.app/v1/transcribe \
-H "Authorization: Bearer kk_..." \
-F model=whisper-1 \
-F language=tr \
-F response_format=json \
-F prompt="Fatura kes, müşteri, vergi kimlik numarası, KDV." \
-F file=@kayit.m4alet boundary = "kilikon-\(UUID().uuidString)"
var req = URLRequest(url: URL(string: "https://api.kilikya.app/v1/transcribe")!)
req.httpMethod = "POST"
req.setValue("Bearer kk_...", forHTTPHeaderField: "Authorization")
req.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
func add(_ s: String) { body.append(s.data(using: .utf8)!) }
let nl = "\r\n"
add("--\(boundary)\(nl)Content-Disposition: form-data; name=\"model\"\(nl)\(nl)whisper-1\(nl)")
add("--\(boundary)\(nl)Content-Disposition: form-data; name=\"language\"\(nl)\(nl)tr\(nl)")
add("--\(boundary)\(nl)Content-Disposition: form-data; name=\"file\"; filename=\"audio.m4a\"\(nl)")
add("Content-Type: audio/m4a\(nl)\(nl)")
body.append(try Data(contentsOf: audioURL))
add(nl + "--\(boundary)--\(nl)")
req.httpBody = body
let (data, _) = try await URLSession.shared.data(for: req)Response
{
"text": "Ahmet Yıldırım'a beş bin lira KDV dahil catering faturası kes",
"raw": "Ahmet Yıldırım'a beş bin lira KDV dahil catering faturası kes"
}
Response alanları
- Audit: Kullanıcının gerçekten ne dediğini doğrulamak (filter yanlış mı sildi?).
- Debug:
textboş döndüyse Whisper hiç bir şey üretmedi mi, yoksa filter mi kesti? - Özel filtreleme: Muhasebe dışı (sağlık, hukuk vb.) bağlamda kendi filtrenizi uygulayacaksanız.
- Çoklu dil / karışık içerik: Filter Türkçe muhasebe için tuned.
text === raw'dır (filter gürültü yakalamadıysa).
Üretimde: Sadece text alanına bak. raw sadece debug ve audit içindir; UI'da kullanıcıya gösterme.
Speech (TTS)
eleven_multilingual_v2 — Türkçe için en doğal ses kalitesi. OpenAI TTS otomatik fallback (ElevenLabs hata verirse). MP3 binary döner.
Yazıyı sese çevirir (TTS). Asistanın cevabını kullanıcıya konuşturma. ElevenLabs eleven_multilingual_v2 modeli Türkçe için iOS native AVSpeech'ten kat kat doğal. OpenAI'a fallback otomatik.
Request
fg8pljYEn5ahwjyOQaro (Türkçe kadın ses). Kendi sesini klonlamak için ElevenLabs üzerinden ID alıp gönderebilirsin.Response Headers
audio/mpeg — MP3 binary.elevenlabs veya openai. ElevenLabs başarısız olursa worker otomatik OpenAI'a düşer ve bu header ile hangi sağlayıcının kullanıldığını bildirir. UI'da log'lamak / analytics için kullan.curl https://api.kilikya.app/v1/speech \
-H "Authorization: Bearer kk_..." \
-H "Content-Type: application/json" \
-d '{
"text": "Merhaba, fatura hazır.",
"voice_id": "fg8pljYEn5ahwjyOQaro",
"stability": 0.45,
"similarity_boost": 0.8,
"style": 0.15
}' \
-D headers.txt \
-o cevap.mp3
# Hangi sağlayıcı kullanıldı?
grep -i "X-TTS-Provider" headers.txt
afplay cevap.mp3 # macOSstruct SpeechRequest: Encodable {
let text: String
let voice_id: String
let stability: Double
let similarity_boost: Double
let style: Double
}
var req = URLRequest(url: URL(string: "https://api.kilikya.app/v1/speech")!)
req.httpMethod = "POST"
req.setValue("Bearer kk_...", forHTTPHeaderField: "Authorization")
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = try JSONEncoder().encode(SpeechRequest(
text: "Merhaba, fatura hazır.",
voice_id: "fg8pljYEn5ahwjyOQaro",
stability: 0.45,
similarity_boost: 0.8,
style: 0.15
))
let (data, response) = try await URLSession.shared.data(for: req)
if let http = response as? HTTPURLResponse,
let provider = http.value(forHTTPHeaderField: "X-TTS-Provider") {
print("TTS provider:", provider) // "elevenlabs" veya "openai"
}
// MP3 binary'sini oynat
let player = try AVAudioPlayer(data: data)
player.play()const resp = await fetch("https://api.kilikya.app/v1/speech", {
method: "POST",
headers: {
"Authorization": "Bearer kk_...",
"Content-Type": "application/json"
},
body: JSON.stringify({
text: "Merhaba, fatura hazır.",
voice_id: "fg8pljYEn5ahwjyOQaro",
stability: 0.45,
similarity_boost: 0.8,
style: 0.15
})
});
console.log("Provider:", resp.headers.get("X-TTS-Provider"));
const blob = await resp.blob();
const url = URL.createObjectURL(blob);
new Audio(url).play();Cevap doğrudan audio/mpeg binary'dir. Tarayıcıda <audio>, iOS'ta AVAudioPlayer, Android'de MediaPlayer ile oynatabilirsin. X-TTS-Provider header'ı ile hangi sağlayıcının kullanıldığını öğrenebilirsin — fallback durumunu analytics'e gönder.
Usage
Bu ay/bugün kaç istek attın, kaç token harcadın? UI'da progress bar göstermek için. Reset gece yarısı UTC'de.
Response
{
"tenantId": "t_a1b2c3d4",
"plan": "starter",
"today": { "requests": 142, "tokens": 18420 },
"limit": { "requests": 500, "tokens": 500000 }
}
Health
Servisin ayakta mı? Uptime monitoring + deploy doğrulama. Auth gerektirmez.
Response
{
"ok": true,
"version": "2.0.0",
"model": "gpt-4o-mini",
"hasKey": true,
"kv": true
}
KVKK Uyumluluğu
KOBİ müşterin Kilikon ile fatura kestiğinde, kişisel veri (müşterinin VKN'si, telefonu, ses kaydı) ABD'deki OpenAI / ElevenLabs / Cloudflare sunucularına gidiyor. 6698 Sayılı KVKK Madde 9 bu yurt dışı aktarım için açık rıza şartı koyar. Bu bölüm hem entegratör (sen) hem son kullanıcı için sorumlulukları net hatlarla gösterir; aşağıdan örnek aydınlatma metnini PDF olarak indirip kendi şirketinin bilgileriyle uyarlayabilirsin.
Kilikon AI'nin son kullanıcı verisini işleme süreci, Türkiye 6698 Sayılı Kişisel Verilerin Korunması Kanunu (KVKK) ile GDPR-uyumlu Avrupa Standart Sözleşme Maddeleri (SCC) çerçevesinde yürütülür. Entegratör (sen) veri sorumlusu sıfatıyla son kullanıcıya karşı KVKK yükümlülüğünü taşırsın; Kilikya ise veri işleyen olarak hizmet sunar ve alt-işleyen (OpenAI, ElevenLabs, Cloudflare, Anthropic) sözleşmelerini sana karşı garanti eder.
Yapay zekâ çağrıları (fatura sohbeti, ses kaydı, fatura/kaşe fotoğrafı) ABD'deki bulut sağlayıcılara iletildiği için KVKK Madde 9 yurt dışı aktarım hükümleri uygulanır. Kullanıcıdan açık, bilgilendirilmiş, geri alınabilir rıza almadan Kilikon endpoint'leri çağrılmamalıdır.
Alt-işleyenler (subprocessor) ve veri akışı: Cloudflare Workers (USA) → OpenAI (USA, model çağrıları) / ElevenLabs (USA, TTS) / Anthropic (USA, /v1/assist asistanı). Her biri SCC + DPA imzalıdır. Kilikya tarafında 30 günden uzun log saklanmaz, log içeriği prompt + tenant ID ile sınırlıdır; PII çıktıları (VKN, telefon, e-posta) maskelenir.
| Konu | Kilikya | Sen (entegratör) |
|---|---|---|
| Worker güvenliği | ✓ | — |
| OpenAI / ElevenLabs DPA + SCC | ✓ | — |
| Veri saklama (worker) | ✓ (30 gün max, sadece istatistik) | — |
| Kullanıcı onam UI | Şablon sağlanır | ✓ Senin app'inde göster |
| Aydınlatma metni | PDF + Markdown verilir | ✓ Şirket bilgileriyle uyarla |
| Onam log'u | — | ✓ 5 yıl sakla |
| VERBİS kaydı | — | ✓ Senin sorumluluğunda |
Önerilen Akış
- Kullanıcı uygulamayı ilk açtığında Kilikon özelliklerine erişmeden önce tam ekran onay modal'ı göster.
- Modal'da bilgi: hangi veri toplanıyor, nereye gidiyor, saklama süresi, hakları, onay geri çekme yolu.
- "Kabul ediyorum" → tarih + versiyon + kullanıcı ID UserDefaults/SharedPrefs'e yazılır.
- Ayarlar > Gizlilik'te "Onayı geri çek" seçeneği şart. Geri çekildikten sonra Kilikon endpoint'i çağrılmamalı.
iOS için hazır SwiftUI component (KilikonConsentView) iOS SDK içinde mevcut. Android için aynı UX'i Compose ile uygulayabilirsin (sample yakında).
Örnek KVKK Aydınlatma Metni
Avukat tarafından gözden geçirilmiş, Kilikon'a özgü subprocessor akışını içeren bir örnek aydınlatma metni hazırladık. Kendi şirket bilgilerinizle (ünvan, KEP adresi, VERBİS kayıt no, başvuru e-postası) değiştirip son kullanıcıya sunabilirsiniz. Bu metin şablondur, hukuki danışmanlıkla birlikte uyarlanması önerilir.
📄 Örnek KVKK Aydınlatma Metnini İndir (PDF)
11 bölüm · A4 · Kilikya Hukuk ekibi tarafından son kullanıcıya yönelik hazırlandı · Markdown kaynağı: KVKK.md
SDK'lar & Örnekler
Her platform için minimal, dependency'siz client örnekleri hazırladık. SDK olarak kullanmak zorunlu değil — istersen kendi HTTP client'ını kullanabilirsin, API REST + JSON standart.
examples/swift/KilikonClient.swift
~150 satır, Foundation only.
examples/kotlin/KilikonClient.kt
OkHttp 4 + Coroutines + Moshi.
examples/javascript/kilikon-client.js
Vanilla fetch, Node 18+ ve browser.
examples/python/kilikon_client.py
requests-based, async opsiyonel.
examples/curl/test-all.sh
Tüm endpoint'leri test eden bash.
openapi.yaml
Postman / Swagger UI import.
Sürüm Notları
1.0.0 — 4 Haziran 2026
İlk stable release. Production'a hazır.
- Multi-tenant Bearer token auth + KV rate limiting
- 8 endpoint: invoice/converse, chat, report, vision, transcribe, speech, usage, health
- Server-side Whisper hallucination filter
- Türkçe muhasebe prompt bias
- Admin panel (tenant CRUD + canlı analytics)
- Multi-language client örnekleri (Swift, Kotlin, JS, Python, curl)
Roadmap
- 1.1 — Temmuz: Webhook desteği (Pro/Enterprise), SSE streaming
- 1.2 — Ağustos: Batch endpoint, audit log export
- 2.0 — Q4 2026: Embedding endpoint, fine-tuned KOBİ modeli
Kilikya Teknoloji A.Ş. · support@kilikya.tr · Wireframe Rehberi →