Kime: DoWaba panelini kendi uygulamasından (headless) kullanan geliştirici partner'lar. Özellikle Trusted Partner OAuth ile bağlanıp kullanıcı adına panel API'larını çağıranlar için.
Bu doküman neden var: API Dokümantasyonu (
/api-docs/) endpoint'leri API grubuna göre dizer — eksiksiz referans ama "panelde gördüğüm şeyin API karşılığı ne?" sorusuna doğrudan cevap vermez. Bu rehber panelin sol menüsünü takip eder: her menü için → ne işe yarar · paneldeki form/alanlar · hangi endpoint · örnek istek · örnek yanıt. İkisi birbirini tamamlar:
İhtiyaç Kaynak "Hangi menü hangi endpoint, akış nasıl?" Bu doküman "Bu endpoint'in tam validasyon alanları neler?" API Dokümantasyonu — her endpoint'te alan listesi Postman / OpenAPI 3 /api-docs/collection.json·/api-docs/openapi.yamlÇalışan örnek projeler Örnek Projeler Toplu gönderim / pazarlama uyum kuralları § 0.6 — opt-out + İYS + KVKK (ZORUNLU) API'lerde ne değişti? (yeni endpoint / kural değişikliği) Panelde: Geliştirici → Sürüm Notları (canlı, sürümlü) — bkz. § 13
Senin uygulaman kendi users tablosunu tutmuyor; kullanıcılar DoWaba'nın user havuzunda.
Uygulaman, kullanıcı adına DoWaba'nın panel API'larını (sites, conversations, contacts…) çağırıyor —
sanki kullanıcı DoWaba'nın resmi mobil uygulamasındaymış gibi. Bunu sağlayan şey sanctum_token.
issues_sanctum_token özelliğini açar.
Bu, sözleşmeli partner için elle açılır — self-service panelden açılamaz.POST /api/oauth/token çağırır (grant_type=authorization_code).{
"access_token": "doat_...",
"id_token": "eyJ...",
"refresh_token": "dort_...",
"expires_in": 3600,
"scope": "openid profile email",
"sanctum_token": "12|abc...", // ← panel API'ları için BU
"sanctum_token_type": "Bearer"
}
sanctum_tokengelmiyorsa: client trusted partner değil veya kullanıcı superadmin (superadmin trusted partner app'lere giremez — onay ekranında bloklanır).
curl https://dowaba.com/api/sites \
-H "Authorization: Bearer 12|abc..." \
-H "Accept: application/json"
https://dowaba.com/apiAccept: application/json ŞART — yoksa auth hatası HTML/redirect dönebilir (302/500 görürsün). Her zaman gönder.reseller_id dolu), sanctum_token ile konuşma/mesaj endpoint'leri
çalışmaz — inbox/unified, {kanal}/conversations, {kanal}/messages/..., inbox/media,
voice transkriptleri, widget sohbetleri boş liste veya 403 döner. Fallback YOKTUR. Gerekçe:
bu token senin (partner'ın) elindedir; bayi müşterisinin konuşmaları yalnız kendi panel
oturumuna açıktır. Site/profil yönetim endpoint'leri (entegrasyon, ayarlar, kişiler,
kampanya) çalışmaya devam eder. Bağımsız (bayiye bağlı olmayan) kullanıcılar için kısıt yok.sanctum_token'ın süresi dolmaz; yalnızca OAuth revoke veya refresh rotation ile silinir
(mobil "logout" = POST /api/oauth/revoke).GET /api/auth/user # oturum açan kullanıcı: id, name, email, role, reseller_id,
# allowed_modules, assigned_site_id, is_agent_only ...
GET /api/user # profil detayları
allowed_modules alanı kritik: kullanıcı kısıtlıysa (sub-user / bayi müşterisi / agent) bu bir whitelist
(["whatsapp","mail",...]). null ise tüm modüller açık. Bir menü/endpoint'i göstermeden önce buna bak.
{ "success": true, "data": ... } döner; bazı liste endpoint'leri data / profiles
anahtarı altında, bazı konuşma listeleri kök array döner. Her endpoint'in şeklini ilk çağrıda doğrula.401 (token yok/geçersiz), 403 (yetki/scope dışı), 402 (slot/abonelik gerekiyor — site açma),
422 (validasyon), 429 (rate limit).10/dk, outbound çağrı 5/dk, AI iyileştir 20/dk).
Her bölümde belirtildi.Geliştirici anahtarıyla (panelde Geliştirici > API Anahtarları'ndan üretilen dev: token'lar ve
Trusted Partner oauth- token'ları) yapılan tüm istekler kullanıcı başına tek dakikalık sayaçta
toplanır — uç başına ayrı limit değildir. Panel/mobil oturum trafiği bu sayaca girmez.
| Hesap | Limit (istek/dk) |
|---|---|
| Business | 60 |
| Professional | 120 |
| Premium | 300 |
| Ultimate | 600 |
| Bayi | 300 + aktif müşteri × 30 (tavan 1.500) |
| Bayi müşterisi | 60 |
X-RateLimit-Limit + X-RateLimit-Remaining header'ları döner; aşımda
429 { "error": "rate_limited", "limit": ..., "retry_after": <sn> } + Retry-After header'ı.
Retry-After kadar bekleyip yeniden dene — agresif retry döngüsü kurma.GET /api/me/rate-limit
# → 200 { "unlimited": false, "limit": 120, "used": 34, "remaining": 86,
# "window_seconds": 60, "source": "plan" }
# source: plan | reseller | reseller_customer | override | default
API erişimin var ama kullanıcıyı tarayıcıda panele sokmak istiyorsan (örn. kendi arayüzünde "Panele Git" butonu):
POST /api/oauth/login-link
# Bearer: sanctum_token (yalnız 'oauth-' Trusted Partner PAT; panel/'api-token' → 403)
# → 200 { "success": true, "url": "https://<marka-host>/admin/impersonate?token=...",
# "expires_at": "...", "expires_in_seconds": 300 }
# → 403 token Trusted Partner değilse · 422 pasif/askıdaki hesap
url'i kullanıcının tarayıcısında aç. Tek-kullanımlık + 5 dk TTL; POST /api/auth/impersonate-redeem
ile redeem edilir (değişmedi). Reseller paneldeki customers/{user}/login-link'in OAuth karşılığıdır.url host'u markaya göre döner (msg724.com / bayi özel domain / dowaba.com). Mimari: OAUTH_PROVIDER.md § 6.1.inbox/unified, {kanal}/messages/..., inbox/media, contacts gibi endpoint'ler WhatsApp / Instagram / Messenger
mesaj içeriği + telefon + isim + medya (Meta Verisi) döndürür. Bu veriyi çekmek = Meta Verisi'nin 3. tarafça işlenmesi →
Meta Platform Terms + WhatsApp Business Solution Terms'e tabidir. Kurallar (DoWaba Partner Sözleşmesi ile bağlayıcı):
me/developer-terms), (2) son kullanıcının açık onayı (OAuth consent). Onaylanmayan veri kategorisine erişme.Özet: "İşletme kendi DoWaba verisi için senin aracını kullanıyor" = uygun. "Sen DoWaba verisiyle kendi ürününü besliyorsun" = ihlal.
scheduled-jobs, contacts/groups/{id}/send-template, mail-campaigns gibi toplu / kampanya gönderim
endpoint'lerini çağırıyorsan Türkiye mevzuatı (ETK 6563 + İYS + KVKK) senin entegrasyonun için de geçerlidir —
panelden manuel gönderim ile API üzerinden gönderim aynı hukuki yükümlülüğe tabidir. Üç kural:
1. Red (opt-out) listesi — DAİMA uygula. Alıcı "DUR / STOP / İPTAL" yazdıysa veya elle çıkarıldıysa kanal-bağımsız
suppression listesine (message_opt_outs) düşer. Bu kişilere gönderim yapılamaz.
scheduled-jobs (zamanlı) hem send-template (anlık toplu) yolları opt-out + İYS reddini otomatik filtreler
(red'li alıcı gönderilmez, kotadan düşmez; yanıtta skipped sayısı + skipped_samples döner).call): alıcı kampanya araması sırasında "beni bir daha aramayın" derse
sesli bot bunu otomatik kaydeder (channel=call opt-out) ve çağrıyı kibarca kapatır; voice-campaigns o numarayı
sonraki aramalarda arama anında atlar (alıcı skipped, skip_reason: opt_out — § 5).GET /api/message-opt-outs?site_id=12&channel=whatsapp
ile listeyi çekebilirsin.2. İYS onayı — pazarlamada ön onay zorunlu. Ticari/pazarlama içerikli toplu mesaj için alıcının önceden onayı
iys/consents ile yükle/sorgula (§ 4). Onaysız liste =
hukuka aykırı + Meta ban riski. (Mevcut müşteriye onaysız kampanya da yasaktır — istisna yalnız değişiklik/bakım bildirimidir.)3. KVKK aydınlatması — botu kapatırsan SEN sorumlusun. Bir konuşmada toggle-bot ile AI'yı kapatıp kendi
uygulamandan cevaplıyorsan, DoWaba'nın otomatik KVKK aydınlatması (son alıcının ilk mesajında gönderilen) devreye
girmez — aydınlatma AI cevabına bağlıdır. Bu durumda son alıcıya KVKK aydınlatmasını sen sağlamak zorundasın
(veri sorumlusu = DoWaba hesap sahibi; sen onun adına işleyensin → Partner Sözleşmesi).
Red (opt-out) listesi endpoint'leri:
GET /api/message-opt-outs?site_id=12&channel=whatsapp # red listesi — channel: whatsapp | sms | mail | call
POST /api/message-opt-outs { "site_id": 12, "channel": "call", "identifier": "+905551112233", "reason": "telefonla beni aramayın dedi" }
DELETE /api/message-opt-outs/{id}
identifier= telefon (whatsapp/sms/call, E.164) veya e-posta (mail) — sistem normalize eder. Yanıt sayfalıdır (data, total, current_page, last_page).channel=callsesli arama kampanyalarının (§ 5) red listesidir; kaydı silmek numarayı tekrar aranabilir yapar.
DoWaba sol menüsündeki sırayla:
| Sol menü | Bölüm | Ana endpoint(ler) |
|---|---|---|
| Siteler | §1 | sites, sites/{site}/faqs, sites/{site}/documents, sites/{site}/functions |
| Mesaj Kutusu (Inbox) | §2 | inbox/unified, inbox/mark-read, inbox/media/... |
| Kanallar (WhatsApp · Telegram · Messenger · Instagram · X · TikTok · Mail · Widget · Google Yorumlar) | §3 | {kanal}/conversations, {kanal}/messages/..., {kanal}/send |
| Rehber & WP Kampanya | §4 | contacts/groups, contacts/..., scheduled-jobs |
| Şablonlar / Kampanyalar (+ Çağrı Kampanyası) | §5 | whatsapp/templates, mail-templates, mail-campaigns, voice-campaigns |
| Reklam Yönetimi (Meta Ads) | §5.5 | ads/accounts, ads/studio/*, ads/campaigns, ads/insights, ads/guard |
| Çağrılar (Voice) + Outbound + Santral | §6 | sites/{site}/voice-conversations, voice/call, sites/{site}/transfer-targets, outbound-intents, outbound-messages |
| Müşteri Talepleri (Callback) | §7 | callback-requests |
| Potansiyel Müşteriler (Leads / CRM) | §7.5 | leads, leads/scan, leads/{id}/stage, leads/{id}/assign, leads/{id}/activities |
| Bilgi Tabanı (site içi: SSS + Belge) | §8 | sites/{site}/faqs, sites/{site}/documents |
| Kullanım & Krediler / Abonelik | §9 | me/usage, credits, subscriptions/*, ai-credit/* |
| Geliştirici (kendi token/webhook/oauth + ChatGPT MCP) | §10 | me/tokens, webhook-endpoints, me/oauth/clients, https://dowaba.com/mcp |
| Profil & Ayarlar | §11 | auth/user, user, settings |
| Faturalarım / Bayi (+ Referans Programı) | §12 | me/billing, reseller/*, reseller/referral/* |
Atlananlar / kısmi (2026-07-15 güncellendi): Paylaşım (
social-posts/*,youtube/*,facebook-page/*) — kısmi/deneysel (YouTube videoları compliance audit'e kadar PRIVATE, IG publish scope App Review'da). Randevu (ayrı modül, site'taappointmentmodülü gerektirir), Trendyol Q&A (trendyol/*). İhtiyaç olursa aynı şablonla eklenir.
Ne işe yarar: Bir "site" = bir AI asistan yapılandırması (sistem promptu, dil, widget ayarı, bağlı kanallar).
Her şeyin merkezi; çoğu endpoint sites/{site}/... altındadır.
Paneldeki form (Yeni Site): ad, açıklama, sistem promptu, dil(ler), (opsiyonel) domain.
GET /api/sites
{ "success": true, "data": [ { "id": 12, "name": "Örnek Mağaza", "is_active": true, "api_key": "...", ... } ] }
GET /api/sites/{site}
POST /api/sites
Content-Type: application/json
{ "name": "Örnek Mağaza", "description": "...", "settings": { "system_prompt": "Sen ...", "languages": ["tr"] } }
402 + onay gerekir → onaylanınca yıllık lisanslı site açılır.403 requires_upgrade.settings.system_prompt max 50.000 karakter.Bayi, müşteri adına site açar:
POST /api/reseller/customers/{user}/sites(§12).
PUT /api/sites/{site} # ad, sistem promptu, ayarlar (settings.widget_theme dahil)
DELETE /api/sites/{site} # KVKK: anonymize + soft delete (30 gün geri alınabilir)
POST /api/sites/{site}/restore # 30 gün içinde geri al
POST /api/sites/{site}/regenerate-key # API anahtarını yeniden üret (widget vb.)
POST /api/sites/{site}/widget-theme/ai # { "prompt": "koyu lacivert, altın vurgulu" } → AI widget tema ÖNERİSİ
POST /api/sites/{site}/auto-messages/beautify # { "field": "ai_error", "text": "..." } → AI ile güzellenmiş metin ÖNERİSİ
widget-theme/aiyalnız öneri döner ({theme, summary}); kalıcı kayıt için dönenthemeobjesiniPUT /api/sites/{site}ilesettings.widget_themealanına yaz (10 renk#RRGGBB+launcher_icon).
Otomatik mesajlar (2026-06-12): AI cevap veremediğinde müşteriye giden sistem metinleri site
bazında özelleştirilebilir: PUT /api/sites/{id} ile settings.auto_messages.{unpaid_notice|ai_error}.
Alan boş/yok ise sitenin birincil dilinde hazır metin gönderilir. auto-messages/beautify
(field: unpaid_notice | ai_error; text opsiyonel — boşsa varsayılan baz alınır) yalnız öneri
döner ({success, text}), kaydetmez.
GET /api/sites/{site}/domains
POST /api/sites/{site}/domains { "domain": "magaza.com" }
POST /api/domains/{domain}/verify
DELETE /api/domains/{domain}
Ne işe yarar: 8+ kanalın tek birleşik listesi. Panelin "Mesaj Kutusu"nun aynısı. Tek istekte tüm kanalların konuşmalarını + okunmamış sayaçlarını verir (yoksa kanal başına ~35 ayrı istek atman gerekir).
GET /api/inbox/unified
GET /api/inbox/unified?filter=unread # sadece okunmamışlar
GET /api/inbox/unified?channel=whatsapp # tek kanal (sayfa boyu 500'e çıkar)
GET /api/inbox/unified?offset=50 # sonraki sayfa (2026-07-14, aşağıya bak)
GET /api/inbox/unified?fresh=1 # cache (15s) bypass
{
"conversations": [
{ "channel": "whatsapp", "identifier": "+905551112233", "profile_id": 4,
"display_name": "Örnek Müşteri", "last_message": "...", "unread": 2, "bot_active": true, "timestamp": "..." }
],
"counts": { "whatsapp": 3, "telegram": 1 },
"totals": { "unread": 4 },
"hasMore": true,
"pageSize": 50,
"offset": 0
}
Sayfalama (2026-07-14): liste kanal başına pageSize konuşma döner (varsayılan 50, channel=X
seçiliyken 500). hasMore=true ise sonraki sayfayı offset += pageSize ile iste; offset>0
yanıtlarında counts/totals null gelir (ilk sayfadaki değerler geçerlidir).
Sayaç birimi (2026-07-14): counts.*.unread ve totals.unread okunmamış konuşma sayısıdır
(mesaj adedi değil) — totals.total ile aynı birim. Konuşma başına mesaj adedi tile'daki unread
alanında kalır.
channel + identifier (+ gerekiyorsa profile_id) ikilisi, kanal bölümlerindeki (§3) mesaj/gönder
endpoint'lerine girdi olur.
POST /api/inbox/mark-read
{ "channel": "whatsapp", "identifier": "+905551112233", "profile_id": 4 }
Bot/operatör cevabı dış API'ye anlık reddedilirse (Meta 5xx/429/bağlantı hatası) mesaj failed
kalır — kaybolmaz. Arka planda kademeli otomatik retry (5/15/45dk, maks 3) çalışır; ek olarak
panelden "Tekrar dene" bu endpoint'i tetikler:
POST /api/inbox/messages/{channel}/{id}/retry # channel: whatsapp | instagram | messenger | telegram
# → 200 { "success": true, "delivery_status": "sent", "message_id": "..." }
# → 422 mesajlaşma penceresi (24 saat) kapalıysa (TG'de pencere yok)
GET /api/inbox/media/{channel}/{messageId} # channel: whatsapp | instagram | telegram | messenger
GET /api/inbox/media/{channel}/{messageId}?download=1
GET /api/inbox/media-signed/{channel}/{messageId} # imzalı varyant — Authorization header GEREKMEZ
İmzalı varyantın URL'ini kendin üretme: kanal mesaj listesi yanıtlarındaki media_signed_url alanı hazır
imzalı gelir (24 saat geçerli, sonra 403). Medyayı kendi arayüzünde <img>/<video>/<audio> src'ına
doğrudan koyacaksan bunu kullan — auth'lu /inbox/media/... tarayıcı media etiketlerinde header
gönderilemediği için 401 alır. Sunucu tarafı indirme için Bearer'lı /inbox/media/... kullanmaya devam et.
Tüm mesajlaşma kanalları aynı 4 adımlı pattern'i izler:
GET {kanal}/conversationsGET {kanal}/messages/{identifier}POST {kanal}/send (Instagram/X/TikTok/Mail'de farklı isim)POST {kanal}/toggle-botBot mantığı:
toggle-botile bir konuşmada AI'yı kapatırsan, o konuşmaya sen (operatör) cevap yazarsın. Açık bırakırsan gelen mesaja AI otomatik cevap verir.toggle-blockile konuşmayı engellersin.
Sayfalama (mesaj listesi) — 2026-06-07:
{kanal}/messages/...varsayılanda konuşmanın tüm geçmişini döndürür (geriye dönük uyumlu). Performans için opt-in sayfalama var:?limit=50→ en yeni 50 mesaj +{ messages, has_more, oldest_id }zarfı; daha eski sayfa için?before_id={oldest_id}&limit=50(yukarı kaydırma cursor'ı,oldest_id'yi zincirle).limit/before_idvermezsen eski davranış (tüm mesajlar, düz dizi) aynen korunur — mevcut entegrasyonların bozulmaz. Destekleyen kanallar: WhatsApp · Telegram · Messenger · TikTok DM · X. (Instagram/Mail konuşma-gruplu yanıt verir, Widget/Voice tekil konuşmadır → bunlarda sayfalama yoktur.)limit1–200 clamp.
Paneldeki form (profil ekleme): bağlantı tipi (Evolution QR / Meta Cloud API / Coexistence) + ilgili kimlik bilgileri. Profil = bir WhatsApp numarası.
GET /api/whatsapp/profiles # bağlı numaralar (profiller)
GET /api/whatsapp/conversations # ?profile_id=X ile filtrele
GET /api/whatsapp/messages/{phone} # mesajlar (?limit=50&before_id=... ile sayfala — opsiyonel)
POST /api/whatsapp/send # yanıt gönder
GET /api/whatsapp/conversation-state # ?phone=...&profile_id=... → bot durumu
POST /api/whatsapp/toggle-bot
POST /api/whatsapp/toggle-block
DELETE /api/whatsapp/conversations/{phone}
Gönderme:
POST /api/whatsapp/send
{
"phone": "+905551112233",
"profile_id": 4,
"message": "Merhaba, nasıl yardımcı olabilirim?",
"media_file_id": null // opsiyonel — önce POST /api/media/upload
}
{ "success": true, "data": { "id": 9001, "direction": "out", "status": "sent", "created_at": "2026-06-01T10:00:00Z" } }
Profil yönetimi (kurulum):
GET /api/whatsapp-profiles
POST /api/whatsapp-profiles # profil oluştur
POST /api/whatsapp-profiles/{id}/link-site { "site_id": 12 } # profili siteye bağla
POST /api/whatsapp-profiles/{id}/unlink-site
GET /api/whatsapp-profiles/{id}/linked-sites
# Evolution (QR): POST whatsapp-profiles/evolution/create → GET .../{id}/evolution/qrcode
# Meta Cloud: GET whatsapp-profiles/platform/phones → POST whatsapp-profiles/platform/connect
Endpoint adları kanaldan kanala değişir ama akış aynıdır. Kimlik alanı (identifier) kanala göre farklı:
| Kanal | Konuşmalar | Mesajlar | Gönder | Bot aç/kapa | identifier |
|---|---|---|---|---|---|
GET whatsapp/conversations |
GET whatsapp/messages/{phone} |
POST whatsapp/send |
POST whatsapp/toggle-bot |
phone |
|
| Telegram | GET telegram/conversations |
GET telegram/messages/{chatId} |
POST telegram/send |
POST telegram/toggle-bot |
chat_id |
| Messenger | GET messenger/conversations |
GET messenger/messages/{senderId} |
POST messenger/send |
POST messenger/toggle-bot |
sender_id |
GET instagram/messages |
(mesajlar inline döner) | POST instagram/messages/send |
POST instagram/toggle-conversation-bot |
sender_id |
|
| X (Twitter) | GET x/conversations |
GET x/conversations/{conversationId}/messages |
POST x/reply |
POST x/conversations/toggle-bot |
conversation_id |
| TikTok (yorum) | GET tiktok/conversations |
GET tiktok/conversations/{videoId}/{openId}/messages |
POST tiktok/reply |
POST tiktok/toggle-bot |
videoId+openId |
| TikTok (DM) | GET tiktok/dm/conversations |
GET tiktok/dm/conversations/{openId}/messages |
— | POST tiktok/dm/toggle-bot |
openId |
GET mail/accounts/{id}/messages |
GET mail/messages/{id}/thread |
POST mail/reply |
POST mail/toggle-bot |
hesap + thread | |
| Web Widget | GET widget-chats |
GET sessions/{session} |
POST sessions/{session}/reply |
(yok) | session |
| Google Yorumlar | GET google-reviews |
GET google-reviews/{id} |
POST google-reviews/{id}/reply |
POST google-reviews/{id}/toggle-bot |
review id |
Gönderme gövdesi kanala göre kimlik alanını değiştirir, gerisi aynı kalır:
// Telegram
POST /api/telegram/send { "chat_id": "123456789", "profile_id": 7, "message": "..." }
// Messenger
POST /api/messenger/send { "sender_id": "...", "profile_id": 3, "message": "..." }
// Instagram
POST /api/instagram/messages/send { "sender_id": "...", "message": "..." }
// X
POST /api/x/reply { "conversation_id": "...", "message": "..." }
// Mail
POST /api/mail/reply { "message_id": 88, "body": "...", "subject": "..." }
Profil kurulumu her kanalda benzer:
GET/POST {kanal}/profiles+.../link-site+ OAuth (Instagram/Messenger/TikTok/X/Google →{kanal}/oauth/config|save). Bunlar genelde panel UI'ından yapılır. Tam alanlar API Dokümantasyonu'nda.
POST /api/ai-improve-message { "channel": "whatsapp", "text": "taslak metin" } # kanal-aware
POST /api/sites/{site}/ai-improve-message { "text": "..." } # site-explicit
# → taslağı kanala uygun, kibar versiyona çevirir (20/dk)
POST /api/media/upload (multipart) → { "id": 555 } # sonra send'de media_file_id olarak kullan
GET /api/media
DELETE /api/media/{id}
Ne işe yarar: Kişi/grup yönetimi (CRM) + WhatsApp şablonuyla toplu/zamanlı gönderim.
GET /api/contacts/groups
POST /api/contacts/groups { "name": "VIP Müşteriler" }
PUT /api/contacts/groups/{id}
DELETE /api/contacts/groups/{id}
GET /api/contacts/groups/{id}/contacts
POST /api/contacts/groups/{id}/contacts { "name": "...", "phone": "+90..." }
PUT /api/contacts/{id} # kişi güncelle (ai_instructions dahil — bkz. not)
POST /api/contacts/delete { "ids": [1,2,3] }
DELETE /api/contacts/groups/{id}/contacts # grubu boşalt — TÜM kişileri tek istekte siler (grup kalır, geri alınamaz)
POST /api/contacts/groups/{id}/import (CSV/çoklu)
POST /api/contacts/quick-add # sohbet panelinden hızlı rehbere ekle
GET /api/contacts/lookup-by-channel # ?channel=whatsapp&identifier=+90...
import-urlKendi web siteniz / CRM'inizden kişi listesini DoWaba rehberine çekin.
POST /api/contacts/groups/import-url
{
"name": "Web sitesi lead'leri",
"url": "https://siteniz.com/api/leads.csv", // CSV veya JSON döndüren PUBLIC adres
"api_key": "gizli-anahtar", // opsiyonel
"auth_style": "bearer", // bearer | x-api-key | query
"auto_refresh": false // true → her kampanyada yeniden çekilir
}
email (e-posta/eposta/mail…), ad (name/isim/ad_soyad…), phone (telefon/gsm/cep…). email VEYA telefon en az biri zorunlu.auto_refresh=false (varsayılan): tek-seferlik — bir kez çekilir, statik grup oluşur, API anahtarı saklanmaz.auto_refresh=true: kaynak URL + auth + API anahtarı (şifreli) gruba kaydedilir; kampanya her başladığında liste bu adresten yeniden çekilir (hep güncel).group.id'yi mail/WhatsApp kampanyasında contact_group_id olarak kullanın.Akıllı segment (yalnız superadmin):
POST /api/contacts/segments/owner_reseller/sync→ tüm owner+bayi üyeleri (bayi müşterileri & sub-user hariç), kampanya başlarken canlı kullanıcı sorgusundan tazelenir. Diğer kullanıcılara kapalıdır (403); grup yalnız superadmin'in rehberinde görünür.
Müşteri-bazlı AI talimatı: Bir kişiye özel bot davranışı vermek için
PUT /api/conversation-ai-overrides { site_id, channel, identifier, instructions, is_active }(9 kanalda geçerli; aynı kişi WhatsApp/IG/Mail'den yazsa da aynı talimat uygulanır).
POST /api/contacts/groups/{id}/send-template
{ "template_name": "kampanya_haziran", "site_id": 12, "params": { ... } }
⚠️ Uyum: Bu anlık toplu gönderim de
scheduled-jobsgibi opt-out + İYS reddini otomatik filtreler (red'li alıcı atlanır; yanıttaskipped+skipped_samplesdöner). Yine de pazarlama içerikse alıcıların İYS onayını önceden almış olmalısın (§ 0.6).
GET /api/scheduled-jobs
POST /api/scheduled-jobs # zamanlı toplu gönderim tanımı
POST /api/scheduled-jobs/{id}/toggle
DELETE /api/scheduled-jobs/{id}
GET /api/scheduled-jobs/whatsapp-stats/{contactGroupId}
⚠️
scheduled-jobsile gönderim opt-out + İYS reddini otomatik filtreler (§ 0.6). Onaysız/red listesindeki alıcı atlanır (skipped, kotadan düşmez).
Tek seferlik kampanyaya tarih (2026-06-11): schedule_type=once iken opsiyonel
scheduled_at ("2026-06-12 14:00", Europe/Istanbul) gönderilebilir — kampanya o anda başlar.
Boş bırakılırsa (veya geçmiş tarihse) hemen başlar. hourly/daily tiplerinde yok sayılır.
İYS (İleti Yönetim Sistemi) onaylarını yükle/sorgula. Toplu pazarlama göndermeden önce gerekli — § 0.6.
Bu endpoint'ler
iysmodülü gerektirir (allowed_modules). İYS şu an STUB modda olabilir (summary.stub_mode=true) → gerçek İYS API'sine yazma için hesap credential'ı + production mod gerekir.
GET /api/iys/consents?site_id=12 # kayıtlı onaylar (data, total, sayfalı)
GET /api/iys/consents/summary # { stub_mode, counts }
GET /api/iys/consents/meta # { sources, types, recipient_types } — geçerli enum değerleri
POST /api/iys/consents # tekil onay kaydı
POST /api/iys/consents/attest-group # bir kişi grubuna toplu onay beyanı
DELETE /api/iys/consents/{id}
Tekil onay kaydı:
POST /api/iys/consents
{
"site_id": 12,
"recipient": "+905551112233", // telefon (MESAJ/ARAMA) veya e-posta (EPOSTA)
"type": "MESAJ", // MESAJ | EPOSTA | ARAMA
"status": "ONAY", // ONAY | RET (varsayılan ONAY)
"source": "HS_WEB", // izin kaynağı — geçerli değerler /iys/consents/meta'da
"recipient_type": "BIREYSEL", // BIREYSEL | TACIR
"consent_date": "2026-06-01 10:00:00", // iznin alındığı GERÇEK an (gelecek tarih reddedilir)
"consent_confirmed": true // ZORUNLU — onayın gerçekliğini beyan edersin
}
İYS hesabı (credential) yönetimi:
GET /api/iys/accounts
POST /api/iys/accounts { "iys_code":"...", "brand_code":"...", "iys_username":"...", "iys_password":"...", "environment":"production" }
PUT /api/iys/accounts/{id}
DELETE /api/iys/accounts/{id}
environment:sandbox|production. Credential'lar şifreli saklanır, yanıtta asla açık dönmez.
GET /api/whatsapp/templates
POST /api/whatsapp/templates # şablon oluştur (Meta'ya gider)
PUT /api/whatsapp/templates/{id}
POST /api/whatsapp/templates/add-optout-button # şablona otomatik QUICK_REPLY "Durdur" ekler → Meta re-review (PENDING); alıcı butona basınca opt-out suppression
DELETE /api/whatsapp/templates/{name}
POST /api/whatsapp/upload-header-image
GET /api/whatsapp/db-columns # şablon değişkenleri için sütun listesi
GET /api/mail-templates
POST /api/mail-templates
POST /api/mail-templates/generate { "prompt": "..." } # AI ile şablon üret
POST /api/mail-templates/{id}/preview
POST /api/mail-templates/{id}/send-test
GET /api/mail-campaigns
POST /api/mail-campaigns
POST /api/mail-campaigns/{id}/start | /pause | /resume | /retry-failed
GET /api/mail-campaigns/{id}/logs
GET /api/mail-campaigns/{id}/preview-recipients
Ne işe yarar: Rehber grubundaki (CSV import dahil — contacts/groups/{id}/import, § 4) numaraları
site'ın sesli botu sırayla arar; sonuç alıcı bazında izlenir. Menü: Kampanyalar → Çağrı Kampanyası.
GET /api/voice-campaigns?status=running # liste — status: draft|running|paused|completed|cancelled
POST /api/voice-campaigns # { site_id, contact_group_id, name, initial_message?, prompt_override?, scheduled_at?, consent_source, consent_date, consent_confirmed: true }
GET /api/voice-campaigns/{id} # detay + sayaçlar (total_completed/no_answer/failed/skipped)
PUT /api/voice-campaigns/{id} # yalnız status=draft
DELETE /api/voice-campaigns/{id} # running/paused silinemez (önce cancel)
POST /api/voice-campaigns/{id}/start | /pause | /resume | /cancel
POST /api/voice-campaigns/{id}/retry-failed # no_answer + failed → tekrar kuyruğa (skipped ASLA yeniden aranmaz)
GET /api/voice-campaigns/{id}/recipients # alıcılar — status: pending|calling|completed|no_answer|failed|skipped
422 {"error":"consent_required"} dönerse eksik sözleşmeleri
POST /api/consent/channel/voice_campaign/accept ile kabul et (panel modalının muadili); kabul AuditLog + mail
kopyasıyla damgalanır.consent_source + consent_date + consent_confirmed: true zorunlu — listenin İYS
ARAMA onayına sahip olduğunu beyan edersin (alıcı bazında marketing_consents ARAMA delili otomatik yazılır).channel=call opt-out'lu (§ 0.6) veya İYS RET'li numara otomatik
atlanır — alıcı skipped + skip_reason: opt_out | iys_denied, kota harcanmaz.message_opt_outs channel=call) ve kibarca kapatır; numara sonraki tüm kampanyalarda atlanır.outbound_call_hours_* + outbound_blocked_weekdays)
dışında arama yapılmaz — kampanya bekler, pencere açılınca devam eder.module:adManagementNe işe yarar: Kullanıcı kendi Meta reklam hesabını bir siteye bağlar; kampanya/görsel oluşturur, performansı izler ve sızıntı koruması kurallarını yönetir. Meta App Review / Advanced Access onayı sonrası 2026-07-15'te tüm kullanıcılara açıldı. Reklam bütçesi DoWaba kredisi değil, kullanıcının Meta hesabından harcanır.
GET /api/ads/oauth/config # browser OAuth URL/config
GET /api/ads/oauth/pending # callback sonrası seçim verisi
GET /api/ads/accounts
POST /api/ads/accounts # seçilen hesap + Sayfa + IG'yi siteye bağla
GET /api/ads/accounts/{id}/edit-options
DELETE /api/ads/accounts/{id}
GET /api/ads/studio/models
POST /api/ads/studio/chat | /generate | /generate-set
GET /api/ads/studio/creatives
GET /api/ads/campaigns?site_id={site}
POST /api/ads/campaigns/sync | /shell
POST /api/ads/campaigns # yeni kampanya; Meta'da PAUSED doğar
POST /api/ads/campaigns/{id}/status | /budget
GET /api/ads/audiences | /interests
POST /api/ads/audiences
GET /api/ads/insights?site_id={site}
GET /api/ads/insights/ads?site_id={site}
GET /api/ads/advisor?site_id={site}
POST /api/ads/advisor | /advisor/apply
GET /api/ads/guard | /guard/actions
PUT /api/ads/guard
POST /api/ads/guard/actions/{id}/apply | /dismiss
GET /api/ads/catalogs?site_id={site} # Commerce Manager deep-link
GET /api/ads/pixels?site_id={site}
POST /api/ads/pixels
accessibleSiteIds() içindeyse erişilir.allowed_modules içinde adManagement yoksa menü ve API 403 ile kapanır.ads_beta_enabled ON durumundadır ve yalnız acil global kapatma kill-switch'i olarak korunur.Tam alan/payload listesi için Scribe'daki Reklam Yönetimi gruplarını kullan; Meta wire kuralları için
meta-ads.md tek otoritedir.
GET /api/sites/{site}/sip-trunk
PUT /api/sites/{site}/sip-trunk
DELETE /api/sites/{site}/sip-trunk
POST /api/sites/{site}/sip-trunk/test
GET yanıtındaki privacy alanı trunk henüz kurulmamışken de site politikasını
döndürür. PUT trunk alanlarına ek olarak şu site-bazlı alanları kabul eder:
{
"voice_privacy_mode": "recorded",
"voice_legal_basis": "explicit_consent",
"voice_controller_name": "Örnek İşletme AŞ",
"voice_privacy_contact": "kvkk@example.com",
"voice_retention_days": 90,
"voice_controller_attested": true
}
recorded, transcript_only, no_retention. Aydınlatmayı
kapatan bir alan veya değer yoktur; voice_notice_required daima true döner.explicit_consent'tir. Diğer seçenekler:
contract_performance, legal_claims, legitimate_interest,
legal_obligation. Seçimin hukuki doğruluğu veri sorumlusu işletmeye aittir.voice_privacy_can_manage bu durumu gösterir.voice_legal_actor_is_owner ve
voice_legal_can_accept kabul POST yetkisini; voice_legal_ready,
voice_legal_missing, voice_legal_acceptance_owner_id ve
voice_legal_owner_action_required owner kanıtının durumunu verir. Bayi,
superadmin veya başka bir aktör kendi legal kabul endpoint'lerini site sahibi
adına çağırmaz; owner kanıtı hazırsa operasyonel trunk ayarını kaydedebilir,
hazır değilse aktivasyon 422 + missing_acceptances döner (devre dışı bırakma
yine mümkündür).voice_controller_attested: true zorunludur ve değişiklik denetim kaydına alınır.voice_controller_name 2-100 karakterlik güvenli işletme-unvanı formatındadır;
voice_privacy_contact yalnız geçerli e-posta veya mutlak https:// adresidir.
Aktif trunk için iki alan da site satırında açıkça bulunmalıdır. Legacy
satırlarda panel site adı/sahip e-postasını yalnız ön-doldurabilir;
voice_privacy_materialization_required=true iken yetkili aktör bu değerleri
voice_controller_attested: true ile kalıcılaştırmadan aktivasyon 422 döner.
sites.voice_retention_days tek otoritedir; trunk üzerindeki aynı isimli alan
yalnız eski istemci aynasıdır.GET /api/sites/{site}/voice-conversations
GET /api/voice-conversations/{id}
GET /api/voice-conversations/{id}/recording-url # imzalı kayıt URL'i
POST /api/voice-conversations/{id}/clean # transkripti AI ile yeniden temizle
POST /api/voice/call { "site_id": 12, "phone": "+90...", ... } # 5/dk
GET /api/sites/{site}/outbound-intents # bekleyen sesli bildirim aramaları
POST /api/sites/{site}/outbound-intents # manuel bildirim araması oluştur
POST /api/outbound-intents/{intent}/approve | /decline | /cancel
GET /api/sites/{site}/outbound-messages # 24h re-engagement mesaj önerileri (WA/TG/Msgr/IG)
POST /api/sites/{site}/outbound-messages # manuel
POST /api/outbound-messages/{intent}/approve | /decline | /cancel
GET /api/outbound-messages/all # tüm sitelerin bekleyenleri (badge)
approve artık declined / cancelled / failed durumundaki
önerileri de kabul eder (tekrar kuyruğa alır, failure_reason temizlenir).
completed/queued/in_progress onaylanamaz → 422 (çift gönderim koruması). 24 saatlik
mesajlaşma penceresi gönderim anında kontrol edilir — pencere kapandıysa öneri anlamlı bir
failure_reason ile failed'e düşer.profile_name eklendi —
mesajın hangi kanal profilinden (bağlı numara/hesap) gideceğini gösterir. Eski kayıtlarda
ve manuel oluşturulan önerilerde null olabilir.Ne işe yarar: Yüksek hacimli telefon trafiği için site başına ek kapasite (eşzamanlı +
günlük + aylık çağrı limitleri). Satın alma abonelik akışında (subscriptions/initiate,
plans yanıtındaki capacity_plans planlarıyla); atama buradan:
GET /api/me/voice-capacity # sahip olunan kapasite paketleri + atandıkları site
GET /api/sites/{site}/voice-capacity # sitenin paketi + anlık eşzamanlı / bugünkü çağrı sayacı
POST /api/sites/{site}/voice-capacity # { "subscription_id": 41 } — paket tek siteye atanır
DELETE /api/sites/{site}/voice-capacity # atamayı kaldır (site default 20 eşzamanlıya döner)
voice-conversations üretilmez. (İç gate:
concurrency_limit / daily_limit — operatör loglarında görünür.)Ne işe yarar: Telefonu AI karşılar; arayan "teknik ekiple görüşmek istiyorum" deyince AI onay alır ve çağrıyı aktarım rehberindeki kişinin telefonuna canlı bağlar. AI serbest numara çeviremez — yalnızca rehberdeki kişiler (sunucu tarafında da doğrulanır).
GET /api/sites/{site}/transfer-targets # rehber + enabled (opt-in) durumu
POST /api/sites/{site}/transfer-targets # { "name": "Ahmet Yılmaz", "department": "Teknik Ekip", "phone": "5551112233", "is_active": true }
PUT /api/sites/{site}/transfer-targets/{target} # kısmi güncelleme
DELETE /api/sites/{site}/transfer-targets/{target}
PUT /api/sites/{site} body { "settings": { "voice_transfer_enabled": true } }.
Kapalıyken AI'ya telefonu_aktar aracı hiç tanımlanmaz, davranış değişmez.90 öneki eklenir
(5551112233 → 905551112233). Site başına en fazla 20 hedef; user_id verilirse
site sahibı veya site ekibinden olmalı (aksi 422).language, BCP-47:
tr/en/ru/de/ar/fr/it) müşterinin konuştuğu dilden farklıysa ve
settings.voice_translate_enabled açıksa, çağrı düz bağlama yerine canlı çift-yönlü
çeviriyle aktarılır: müşteri ve temsilci kendi dilinde konuşur, Gemini sesi anlık çevirir.
transfer-targets yanıtındaki translate_enabled ile durum görünür; hedef oluştururken
language ver (boş = düz aktarım, çeviri yok). Çeviri ek AI kredisi tüketir
(§9, source: voice_translate).voice-conversations yanıtlarında başarılı aktarımlar
status: "transferred" + transferred_to_name / transferred_to_phone /
transferred_at alanlarıyla gelir. recorded moddaki Dowaba kaydı yalnız
aktarım öncesi privacy-gated AI fazını içerir; insan/canlı-çeviri/app aktarım
bacaklarında ses veya transkript saklanmaz. İşletme ayrı bir santral/temsilci
sistemiyle kayıt yapıyorsa itirazı kendi durdurma/silme prosedüründe işlemelidir.Ne işe yarar: AI "sizi geri arayalım" dediğinde / müşteri talep bıraktığında oluşan kayıtlar.
GET /api/callback-requests
PUT /api/callback-requests/{id}/status { "status": "done" }
PUT /api/callback-requests/{id}/note { "note": "..." }
POST /api/callback-requests/{id}/beautify-note # notu AI ile düzelt
Talepler site ekibindeki bir kullanıcıya atanabilir; istenirse yeni talepler ekipteki
agent rolündeki kullanıcılara en az açık talebi olana otomatik dağıtılır.
GET /api/callback-requests/assignment-options?site_id=12 # atanabilir ekip + açık talep sayıları + auto_assign durumu
POST /api/callback-requests/{id}/assign { "user_id": 17 } # null → atamayı kaldır
PUT /api/callback-requests/auto-assign { "site_id": 12, "enabled": true }
{id} = liste yanıtındaki talep kimliği (kanal bazlı konuşma id'si). Site ekibi dışındaki
kullanıcıya atama 422 döner.GET /api/callback-requests) yanıtındaki her kayda assigned_user_id +
assigned_user_name alanları eklendi (atanmamışsa null).module:leadsNe işe yarar: Konuşmalardan / talep / lead-ads kaynaklarından oluşan satış adayları (CRM pipeline:
sürüklenebilir aşamalar + ekip ataması). Yalnız KENDİ sitelerinin lead'leri görünür (bayi, müşteri
sitelerinin lead'lerini göremez — mesaj/rehber gizlilik kilidiyle tutarlı). module:leads gerektirir.
GET /api/leads # liste (site/aşama filtreli)
POST /api/leads # manuel aday ekle (kaynak: manuel/öneri/talep/lead-ads)
POST /api/leads/inbox # Mesaj Kutusu konuşmasından aday ekle (channel + identifier)
GET /api/leads/inbox-status # konuşma zaten lead mi? (yazmaz — idempotent probe)
POST /api/leads/scan # konuşmaları AI ile tara → aday çıkar (10/dk)
POST /api/leads/{id}/analyze # tek adayı AI ile analiz et (10/dk)
GET /api/leads/{id}/activities # değişiklik geçmişi: kim ne yaptı (created/stage_changed/assigned/updated)
PATCH /api/leads/{id}/stage # pipeline aşaması değiştir { "stage": "..." }
POST /api/leads/{id}/assign # ekip üyesine ata { "user_id": 17 } (null → kaldır)
POST /api/leads/reorder # sütun içi sıralama (sürükle)
PATCH /api/leads/{id} # güncelle (ad / telefon / not ...)
DELETE /api/leads/{id} # sil
GET /api/lead-submissions # Lead Ads form yanıtları (Meta/Facebook lead formları — ham gönderimler)
Lead kaynakları: manuel · konuşma taraması (
scan) · Müşteri Talepleri · Lead Ads (Facebook lead formu →POST facebook-page-profiles/{id}/sync-leads,module:publishing→lead-submissions+ otomatik lead). Alan (body) listeleri için /api-docs (Scribe) → "Potansiyel Müşteriler (Leads)" grubuna bak.Değişiklik geçmişi: lead yazma uçları (ekleme / düzenleme / aşama / atama) her değişiklikte otomatik geçmiş kaydı üretir;
GET /api/leads/{id}/activitiesen yeni üstte döner. Kayıt:action,actor_name(sistem işlemlerinde null),actor_role(owner | agent | subuser | system ...), alan bazlıchanges { alan: {from, to} }(atamada okuma anında çözülenfrom_label/to_labelda eklenir). Sürükleme sırası (reorder) bilinçli olarak geçmişe yazılmaz.
Sitenin AI'ının cevap verirken kullandığı bilgi. Hepsi sites/{site}/... altında.
GET /api/sites/{site}/faqs
POST /api/sites/{site}/faqs { "question": "...", "answer": "..." }
PUT /api/faqs/{faq}
DELETE /api/faqs/{faq}
POST /api/sites/{site}/faqs/batch # toplu EKLE (yeni SSS'ler)
POST /api/sites/{site}/faqs/batch-update { "updates": [{ "id": 12, "question": "...", "answer": "..." }] } # toplu DEĞİŞTİR (var olanları)
POST /api/faqs/{faq}/ai-rewrite { "instruction": "5551234567 numarasını kaldır" } # tek SSS'i AI talimatla yeniden yaz
POST /api/sites/{site}/faqs/extract-from-text { "text": "..." } # metinden SSS çıkar (AI)
POST /api/sites/{site}/faqs/extract-from-image (görselden)
DELETE /api/sites/{site}/faqs/delete-all
GET /api/sites/{site}/documents
POST /api/sites/{site}/documents (yükle)
POST /api/documents/{document}/process # parse + embedding
DELETE /api/documents/{document}
GET /api/sites/{site}/functions
POST /api/sites/{site}/functions # DB sorgusu veya HTTP API fonksiyonu tanımla
POST /api/functions/{function}/test
POST /api/functions/{function}/toggle { "site_id": 159, "is_active": false }
# is_active hedef durumu zorunludur (idempotent). Global fonksiyonda site_id de zorunludur;
# merkezi tanım kopyalanmaz/değişmez, yalnız hedef sitenin izole disable listesi güncellenir.
# Siteye özel fonksiyonda site_id gerekmez. Yasal/lifecycle korumalı sistem fonksiyonları 422 döner.
# Harici bağlantılar (DB/HTTP):
GET /api/sites/{site}/connections
POST /api/sites/{site}/connections
POST /api/connections/{connection}/generate-functions # tablodan otomatik fonksiyon üret (AI)
# Hazır modül paketi yükle — connection + TÜM fonksiyonlar tek seferde:
POST /api/sites/{site}/bundles/import { "manifest": { ...JSON... }, "api_key": "<secret>", "replace": true }
# veya dış URL'den: { "manifest_url": "https://...", "api_key": "<secret>" }
# → "manifest" (JSON gövde) ÖNERİLİR: dış URL fetch YOK = SSRF yüzeyi sıfır. manifest|manifest_url biri zorunlu.
# api_key = connection bearer/api_key sırrı; replace=true mevcut paketi günceller (idempotent re-sync).
#
# Fonksiyon şablon değişkenleri (url_template / body_template / headers içinde {{...}}):
# {{arg.X}} → AI'ın doldurduğu fonksiyon argümanı (model/kullanıcı girdisi → DOĞRULANMAMIŞ)
# {{connection.base_url}} ... → connection'ın kayıtlı (şifreli) değerleri
# {{user.id|phone|name|email}} → DOĞRULANMIŞ son-kullanıcı kimliği: web widget'ta imzalı data-user-token'dan
# çözülen kullanıcı, WhatsApp/voice'ta Meta-imzalı telefon. Sistem otomatik
# enjekte eder → AI/kullanıcı SPOOF EDEMEZ. "Giriş yapanın KENDİ verisi"
# isteyen fonksiyonlarda (siparişlerim, derslerim, şifre-sıfırlama) kimliği
# {{arg.*}} parametresi YAPMA → body_template'te {{user.id}}/{{user.phone}}
# kullan. Anonim kullanıcıda boş gelir (istek o alan olmadan gider).
GET /api/me/usage # birleşik mesaj+voice snapshot (dashboard)
GET /api/usage # detay
GET /api/usage/stats
GET /api/credits # bakiye
GET /api/credits/transactions
GET /api/me/credit-summary # header badge için rol-aware özet
GET /api/subscriptions/plans
GET /api/subscriptions/current
GET /api/subscriptions/usage
GET /api/subscriptions/price-quote # ?plan_id=&sites_count= → fiyat
POST /api/subscriptions/initiate { "plan_id": "business", "sites_count": 5 }
POST /api/subscriptions/change-sites
# Ödeme: PayTR (TR), Stripe (USD, otomatik webhook), PayPal (USD, manuel onay)
POST /api/subscriptions/stripe/checkout
POST /api/subscriptions/paypal/initiate
GET /api/ai-credit/catalog
GET /api/ai-credit/summary # bakiye
GET /api/ai-credit/transactions
POST /api/ai-credit/stripe/checkout | /paytr/checkout | /paypal/initiate
Cüzdan neyi fonlar: Kullanıcının (veya bayisinin) kendi Gemini anahtarı yoksa AI maliyetleri bu cüzdandan düşülür — yalnız sohbet mesajları (tüm kanallar) değil, sesli çağrılar (AI'ın karşıladığı telefon, 2026-06-14'ten itibaren) ve canlı çeviri (telefon aktarımında çapraz dil) de.
transactionsyanıtındakisourcealanı kalemi ayırır (ör.voice_conversation,voice_translate). Maliyet gerçek token kullanımından (GeminiusageMetadata) hesaplanır × kâr marjı; sesli kalem metinden pahalıdır (ses çıkışı yüksek oranlı). Bakiye biterse AI yanıt veremez → kullanıcı paket satın almalı (catalog→checkout).
Ne işe yarar: Kullanıcının kendi API anahtarı (Sanctum PAT), outbound webhook ve OAuth client'ı. Senin trusted-partner client'ından AYRIDIR — bu, kullanıcının panelden kendi entegrasyonunu açması içindir.
⚠️ Bu endpoint'lere erişim için kullanıcının
developermodülü açık olmalı (allowed_modules). Ayrıca token/webhook/oauth oluşturmadan önce geliştirici şartları kabulü zorunlu:GET /api/me/developer-terms→POST /api/me/developer-terms/accept.
GET /api/me/tokens
POST /api/me/tokens { "name": "Entegrasyonum" } # 10/dk — plain token bir kez döner
DELETE /api/me/tokens/{id}
GET /api/webhook-endpoints
POST /api/webhook-endpoints { "url": "https://...", "events": ["message.received"] } # 20/dk
PATCH /api/webhook-endpoints/{id}
POST /api/webhook-endpoints/{id}/test
GET /api/webhook-endpoints/{id}/deliveries # gönderim logları
DELETE /api/webhook-endpoints/{id}
Tek event adı
message.received'dır ve tüm gelen-mesaj kanallarında tetiklenir (2026-07-24+): WhatsApp (Cloud API + QR + Coexistence), Instagram DM, Messenger, Telegram, TikTok DM, X DM, Mail, site Widget'ı. Kanalıdata.channelalanından ayırt et (whatsapp|instagram|messenger|telegram|tiktok|x|mail|widget);data.fromkanala göre telefon / platform kullanıcı ID'si / e-posta / widget oturum ID'sidir. Mail ve X-sync geçmiş taramalarında 48 saatten eski mesajlar webhook tetiklemez (backfill koruması).İmza: gelen webhook'larda
X-Dowaba-Signature(HMAC-SHA256) doğrula. ⚠️ Payload müşteri PII'si içerir (telefon/ad/mesaj metni) — varsayılan maskelidir (masked=true: from kısaltılır, ad/metin null); tam içerik yalnız DPA onaylıfull_payload=trueendpoint'lerde gelir ve bu veriyi yalnız veri sahibine hizmet için kullanabilirsin (§ 0.5).
GET /api/me/oauth/clients
POST /api/me/oauth/clients # issues_sanctum_token gövdeden AÇILAMAZ (aşağıdaki ayrı uç)
PATCH /api/me/oauth/clients/{id}
POST /api/me/oauth/clients/{id}/rotate-secret
DELETE /api/me/oauth/clients/{id}
Bayiysen kendi uygulamanı (yan uygulama / white-label panel) kendin Güvenilir Ortak
yapabilirsin: kullanıcı senin uygulamandan "DoWaba ile giriş" yapar, token yanıtında
standart access_token'ın yanında sanctum_token da gelir ve bu token ile panel
API'larını kullanıcı adına çağırırsın (§ 0).
POST /api/me/oauth/clients/{id}/trusted-partner # gövde: {"commitment": true}
DELETE /api/me/oauth/clients/{id}/trusted-partner # kapat
Açılış koşulları (hepsi zorunlu; GET /api/me/oauth/clients yanıtındaki
partner_sso.requirements bloğu hangisinin eksik olduğunu gösterir):
partner_sso.max_trusted_clients) aşmamak, 7. commitment: true ile veri
işleme taahhüdünü onaylamak.Kapsam kilidi: Self-servis açılan uygulamada kapsam daima tenant'tır — bu uygulamaya
yalnız senin kendi evrenin (sen + müşterilerin + alt kullanıcıların) giriş yapabilir.
Evren dışındaki bir kullanıcı consent ekranında engellenir (out_of_scope_reason=tenant_scope),
superadmin hesapları her durumda engellenir. Bayilik aboneliğin/sözleşmen düşerse
uygulamana yeni giriş yapılamaz (owner_gate).
Kapatınca ne olur: Uygulamaya ait tüm OAuth token'ları iptal edilir ve bağlı
sanctum_token'lar silinir — kullanıcılar yeniden giriş yapmak zorunda kalır. Bayilik
aboneliğin/sözleşmen düşerse aynı temizlik otomatik yapılır (günlük partner-sso:sync):
uygulaman Güvenilir Ortak modundan çıkar, mevcut sanctum_token'lar da silinir.
Panelden: Geliştirici → OAuth Uygulamaları → ilgili uygulama kartı → "Güvenilir Ortak (SSO)". Panel giriş linki için
POST /api/oauth/login-link(§ Trusted Partner SSO).
Kendi doğrulanmış özel domain'in varsa (Bayilik → Özel Domain), giriş + izin ekranı senin adresinde açılabilir — kullanıcı URL çubuğunda hep senin markanı görür:
PATCH /api/me/oauth/clients/{id}/branded-host # gövde: {"host": "destek.firma.com"} — temizlemek için {"host": null}
Yalnız kendi yayındaki (active) domain'lerinden biri seçilebilir; seçilebilir liste
GET /api/me/oauth/clients yanıtındaki partner_sso.available_branded_hosts alanındadır.
Ayarlandıktan sonra https://dowaba.com/oauth/authorize?... isteği aynı sorgu parametreleriyle
https://destek.firma.com/oauth/authorize?... adresine 302 ile taşınır — istemci tarafında
yapman gereken bir şey yok (redirect_uri, PKCE, state aynen korunur, iss yine
https://dowaba.com). Domain yayından kalkarsa yönlendirme durur, akış dowaba.com üzerinden
sorunsuz sürer.
Kullanıcı uygulamana ilk girişte izin kartını görür; onayı kaydedilir ve sonraki girişlerde kart
atlanır. GET /api/oauth/authorize/state yanıtındaki has_prior_consent bunu bildirir.
İstediğin scope setini genişletirsen kart yeniden gösterilir. Kullanıcı izni istediği an geri
çekebilir (panel → Bağlı uygulamalar; DELETE /api/me/oauth/consents/{clientId}) — o kullanıcının
sanctum_token'ı ve OAuth token'ları anında geçersiz olur, uygulaman 401 alır ve kullanıcıyı
yeniden "DoWaba ile giriş"e yönlendirmelidir.
Entegrasyonu elle kodlamak istemiyorsan aşağıdaki prompt'u olduğu gibi kopyala, en üstteki köşeli parantezli alanları kendi bilgilerinle doldur ve kullandığın yapay zeka asistanına (Claude, ChatGPT, Cursor, Copilot...) yapıştır. Prompt, asistanın senin uygulamana/CRM'ine uçtan uca çalışan bir "DoWaba ile Giriş" entegrasyonu yazması için gereken tüm teknik gerçekleri içerir — asistanın DoWaba'yı önceden tanımasına gerek yoktur.
Ön koşul: Panel → Geliştirici → OAuth Uygulamaları'ndan client'ını oluştur (Confidential işaretli),
client_id+client_secret'ı kopyala ve Güvenilir Ortak (SSO) modunu aç (yukarıdaki bölüm). İstersen "giriş adresi" olarak kendi özel domain'ini seç — kullanıcıların gördüğü login ekranı senin markanla açılır.
Uygulamama "DoWaba ile Giriş" (OAuth 2.0 + OIDC, Güvenilir Ortak modu) entegre etmeni
istiyorum. Aşağıda sağlayıcının TÜM teknik detayları var — bunlara birebir uy, uydurma.
BENİM BİLGİLERİM (doldur):
- Uygulamam / stack: [ör. Laravel 11 + Blade / Node.js Express + React / Django ...]
- Uygulamamın adresi: [https://uygulamam.com]
- client_id: [dosc_...]
- client_secret: [dosec_...] ← YALNIZ sunucu tarafında kullanılacak
- redirect_uri (DoWaba panelinde kayıtlı olanla BİREBİR aynı): [https://uygulamam.com/oauth/dowaba/callback]
- Giriş adresi (white-label seçtiysem, yoksa dowaba.com): [https://hesap.markam.com veya https://dowaba.com]
SAĞLAYICI GERÇEKLERİ (DoWaba):
1. Authorize (tarayıcı yönlendirmesi): GET {GİRİŞ_ADRESİ}/oauth/authorize
Zorunlu query parametreleri: client_id, redirect_uri, response_type=code,
scope="openid profile email", state (CSRF için rastgele, session'da sakla ve
callback'te doğrula), code_challenge, code_challenge_method=S256.
PKCE ZORUNLUDUR: 64+ karakterlik rastgele code_verifier üret; challenge =
base64url(sha256(verifier)) (padding'siz). Verifier'ı session'da tut.
2. Token (SUNUCUDAN sunucuya): POST https://dowaba.com/api/oauth/token
Body (JSON veya form): grant_type=authorization_code, client_id, client_secret,
code (callback'teki ?code=), redirect_uri (aynısı), code_verifier.
Başarılı yanıt alanları:
access_token ("doat_..." — 1 saat ömürlü, yalnız userinfo için)
id_token (RS256 imzalı JWT; doğrulama anahtarı JWKS'te)
expires_in (3600)
refresh_token ("dort_..." — dönerse sakla; rotation vardır: her kullanımda
YENİSİ döner, eskisini bir daha KULLANMA — tekrar kullanım tüm
token ailesini iptal eder)
sanctum_token ("12|..." — GÜVENİLİR ORTAK ANAHTARI: süresizdir, kullanıcı
adına DoWaba panel API'larını çağırır. ASIL kalıcı erişim budur.)
sanctum_token'ı kullanıcı kaydında ŞİFRELİ sakla; tarayıcıya/frontend'e ASLA verme.
3. Kimlik: GET https://dowaba.com/api/oauth/userinfo
Header: Authorization: Bearer {access_token} → { sub, email, name, ... } döner.
sub = DoWaba kullanıcı ID'si; kendi tablomda kullanıcıyı "dowaba_user_id = sub" ile
eşle (Trusted Partner deseninde kendi şifre/kimlik sistemimi KURMAM — kullanıcı
havuzu DoWaba'dadır; bende yalnız sub + sanctum_token + profil kopyası durur).
4. Kullanıcı adına DoWaba API'ları: Authorization: Bearer {sanctum_token} ile
https://dowaba.com/api/... uçları (örn. GET /api/me, GET /api/sites,
GET /api/conversations). Yetki otomatik olarak kullanıcının kendi kapsamıdır;
BAŞKA kullanıcının verisine erişilemez. Not: kullanıcı bir bayinin müşterisiyse
mesaj İÇERİĞİ uçları bu anahtarla kapalıdır (403/boş) — site/profil yönetimi çalışır.
Tüm uçların dokümanı: https://dowaba.com/api-docs/ ve https://dowaba.com/gelistirici-rehberi
5. Panele geçiş (SSO): POST https://dowaba.com/api/oauth/login-link
Header: Authorization: Bearer {sanctum_token} → {"url": "..."} tek kullanımlık,
5 dk geçerli panel giriş linki döner. Uygulamama "Panele Git" butonu koy, bu URL'e
yönlendir (her tıklamada YENİ link iste, cache'leme).
6. Çıkış / bağlantıyı kesme: POST https://dowaba.com/api/oauth/revoke
Body: client_id, client_secret, token (refresh_token ya da access_token).
Revoke sanctum_token'ı da siler. Kendi session'ımı da temizle.
7. Consent-once: kullanıcı izni İLK girişte bir kez onaylar, sonraki girişler kartsız
akar. Kullanıcı izni DoWaba panelinden geri çekebilir → elimdeki sanctum_token
401 dönmeye başlar. HER 401'de: kayıtlı token'ı sil, kullanıcıyı yeniden
authorize akışına gönder (otomatik dene; kullanıcı hâlâ yetkiliyse kartsız geçer).
8. Kapsam (tenant): Bu client'a YALNIZ benim DoWaba bayi evrenimdeki kullanıcılar
(ben + müşterilerim + alt kullanıcılarım) giriş yapabilir. Kapsam dışı kullanıcı
consent ekranında "bu uygulama size açık değil" görür; uygulamam callback'te
?error=access_denied alabilir → kibar bir hata sayfası göster.
9. Hata durumları: callback'te ?error= gelirse (access_denied vb.) token isteği
YAPMA, hata sayfası göster. Token endpoint'i 4xx dönerse response body'deki
error alanını logla. state uyuşmazsa isteği REDDET (CSRF).
YAPMANI İSTEDİKLERİM:
a) /oauth/dowaba/redirect (giriş başlatma: PKCE + state üret, authorize URL'ine 302)
ve /oauth/dowaba/callback (state doğrula, kodu token'a çevir, userinfo çek,
kullanıcıyı upsert et, session aç) rotalarını yaz.
b) Kullanıcı tablosuna/koleksiyonuma dowaba_user_id (unique) + dowaba_sanctum_token
(şifreli) + email + name alanlarını ekleyen migration/şema değişikliği.
c) "DoWaba ile Giriş" butonu + "Panele Git" (login-link) butonu + "Bağlantıyı kes"
(revoke + yerel çıkış) akışı.
d) sanctum_token ile DoWaba API çağrısı yapan, 401'de token'ı temizleyip yeniden
yetkilendirmeye yönlendiren küçük bir API istemci sınıfı/yardımcısı.
e) Güvenlik kuralları: client_secret ve sanctum_token yalnız sunucuda; tüm istekler
HTTPS; state + PKCE doğrulaması atlanamaz; token'lar loglanmaz.
f) Sonunda elle test adımlarını listele (giriş → panel API çağrısı → login-link →
izin geri çekme → 401 kurtarma).
Kodun tamamını benim stack'ime uygun, çalışır halde yaz. Bilmediğin bir davranışı
varsayma — yukarıdaki gerçeklerle çelişen hiçbir şey ekleme.
Prompt'taki akış klasik "Authorization Code + PKCE" olduğu için asistanın üreteceği kod
standart OAuth kütüphaneleriyle de (Laravel Socialite custom provider, openid-client,
authlib...) uyumludur — asistan kütüphane kullanmayı seçerse endpoint'leri ve
sanctum_token alanını yukarıdaki gibi elle eşlemesi yeterli.
Canonical MCP resource:
https://dowaba.com/mcp
Bu yüzey REST panel API'si değildir; MCP Streamable HTTP + JSON-RPC kullanır.
ChatGPT uygulamasında Dowaba hesabı OAuth Authorization Code + PKCE ile bağlanır.
MCP client public/predefined'dır, resource=https://dowaba.com/mcp ile
audience-bound token alır ve Trusted Partner sanctum_token kullanmaz.
Akış:
expected_revision + idempotency_key ile canlı olmayan taslak oluşturulur.MCP mesaj/konuşma okumaz, mesaj göndermez, bot açıp kapatmaz, credential döndürmez ve site/kanal lifecycle'ına dokunmaz. ChatGPT belleği Dowaba'nın eriştiği bir API değildir; ChatGPT yalnız kullanıcının konuşmada gördüğü yapılandırılmış persona ve doğrulanmış SSS sonucunu gönderir. Ham bellek veya ham konuşma saklanmaz.
Discovery:
GET /.well-known/oauth-protected-resource/mcp
GET /.well-known/oauth-authorization-server
GET /.well-known/openai-apps-challenge
Araç adları, OAuth scope'ları, publish/rollback gate'leri ve üretim runbook'unun
iç operasyon tek otoritesi repo kökündeki MCP.md dosyasıdır. Public entegrasyon
desteği için aydin@dowaba.com ile iletişime geç.
GET /api/auth/user # kimlik + role + allowed_modules (§0.3)
GET /api/user # profil detay
PUT /api/user # profil güncelle
PUT /api/user/locale { "locale": "tr" }
PUT /api/user/menu-settings # sol menü görünürlüğü
GET /api/settings # kullanıcı global ayarları (key-value)
PUT /api/settings
GET/PUT /api/settings/gemini-models # AI model tercihi
GET/PUT /api/settings/whatsapp | /sms | /sip
GET /api/me/billing # bayiden gelen borç + taksit + ödeme
GET /api/customer-invoices/{invoice}/data # fatura JSON (PDF client-side üretilir)
role=reseller)GET /api/reseller/summary # KPI kartları
GET /api/reseller/customers
POST /api/reseller/customers { "name": "...", "email": "...", "phone": "+90..." }
GET /api/reseller/customers/{user}
POST /api/reseller/customers/{user}/send-password-link # müşteriye şifre kurulum bağlantısı (3/saat)
POST /api/reseller/customers/{user}/sites # müşteri adına site + lisans
GET /api/reseller/invoices # bekleyen/ödenmiş lisans faturaları
POST /api/reseller/customers/{user}/billing/invoices # müşteriye fatura kes (cari hesap)
GET /api/reseller/branding # white-label marka
⚠️ Müşteri şifresi (2026-06-11):
POST/PUT /reseller/customers*artıkpasswordparametresi kabul etmez (gönderilirse yok sayılır). Müşteri şifresini, kendisine e-posta/SMS ile giden kurulum bağlantısıyla kendisi belirler (send-password-link; yeni müşteri oluşturmada otomatik gönderilir — yanıttapassword_link_sent+password_link_channel). Bayi müşterisinin konuşma/mesaj içeriğine de erişemez (§ 0.2).
requires_reseller_agreement)Bayi yazma uçları (müşteri ekleme, müşteriye site açma/atama/geri alma, kendi sitesini açma, DID yönlendirme yönetimi, bayilik planı satın alma) güncel bayilik sözleşme paketinin (3 belge) onaylı olmasını şart koşar. Okuma uçları sözleşme sormaz — listeler/raporlar kesilmez.
Sözleşme paketi güncellenirse (yeni sürüm yayınlanır ve yürürlük tarihi ileri çekilirse) eski onaylar geçersiz sayılır ve bu yazma uçları — panel de API de — yeniden onaya kadar şu yanıtı döner:
403 { "success": false, "requires_reseller_agreement": true, "message": "..." }
Entegrasyon tarafında yapılması gereken: 403 + requires_reseller_agreement: true yakalandığında
işlemi kuyruklamayı bırakıp bayi kullanıcıyı onaya yönlendirin. İki yol:
https://<panel>/reseller/agreement sayfasında tek tıkla onaylar (önerilen).GET /api/reseller/agreement # 3 belgenin metni + sha256 + accepted / requires_reacceptance
POST /api/reseller/agreement { "accepted": true, "acknowledged_hashes": { "reseller-agreement": "<sha>", "reseller-mesafeli": "<sha>", "reseller-dpa": "<sha>" } }
⚠️ Onay bayinin bilinçli, insan eylemi olmalıdır — belgeleri kullanıcıya göstermeden arka planda otomatik
POSTetmeyin. Her kabulaudit_logs'a sürüm + sha256 ile kanıt satırı yazar; onayın kim tarafından, hangi metne verildiği yasal delil zinciridir. Not: Referans Programı katılımı aynı ön koşulu tek akışta çözer (422 requires_reseller_bundle, aşağıdaki bölüm).
role=reseller)Ne işe yarar: Bayi, dowaba'ya müşteri yönlendirir; müşteri dowaba'ya öder, bayi hakediş alır (brütün %20'si). Toptan/white-label modelin TERSİ para yönü: müşteri dowaba'nın kendi müşterisidir, bayi onun panel/mesaj verisine erişemez.
Ön koşullar (API'de de geçerli): role=reseller + hesap aktif + bayilik sözleşme paketi
(3 belge) güncel sürümle onaylı + programa katılım (opt-in). Sözleşme eksikse opt-in
422 requires_reseller_bundle döner ve belgeler aynı yanıtta gelir — ayrı sayfaya gitmeden,
tek istekte onaylanır.
| Panel sekmesi | Endpoint(ler) |
|---|---|
| (durum/ön koşul) | GET /api/reseller/referral |
| Programa Katıl | POST /api/reseller/referral/opt-in · POST /api/reseller/referral/opt-out |
| Genel Bakış | GET /api/reseller/referral · PATCH /api/reseller/referral/settings |
| Kanal Kodları | POST /api/reseller/referral/codes · PATCH /api/reseller/referral/codes/{id} |
| Referans Paketlerim | GET/POST /api/reseller/referral/packages · PATCH .../packages/{id} · GET .../packages/modules |
| Müşteriler & Hakedişler | GET /api/reseller/referral/customers · GET /api/reseller/referral/commissions |
| Ödemeler | GET/POST /api/reseller/referral/payouts · GET .../payouts/{id}/invoice |
GET /api/reseller/referral # durum + oranlar + sözleşme metinleri + kodlar + sayaçlar
POST /api/reseller/referral/opt-in { "accepted": true, "acknowledged_sha256": "<sha>" }
POST /api/reseller/referral/opt-out # yeni tahakkuk durur; paketler pasifleşir
PATCH /api/reseller/referral/settings { "public_listed": true, "payout_iban": "TR33...", "payout_iban_holder": "..." }
POST /api/reseller/referral/codes { "label": "Instagram", "code": "INSTA2026" } # link: /register?ref=KOD
PATCH /api/reseller/referral/codes/{id} { "is_active": false } # silme YOK, pasifleştirme
GET /api/reseller/referral/packages/modules # allowed_modules için geçerli anahtar seti
GET /api/reseller/referral/packages # paketler + sales sayaçları + limits (taban katsayıları)
POST /api/reseller/referral/packages { "name","message_quota","voice_quota","sites","allowed_modules"[],"prices"{},"page"{} }
PATCH /api/reseller/referral/packages/{id} { "name"?, "is_active"?, "page"? } # ÇEKİRDEK IMMUTABLE
GET /api/reseller/referral/customers # ad + tarih + abonelik durumu (KVKK-minimal, iletişim bilgisi YOK)
GET /api/reseller/referral/commissions # hakediş defteri (accrued/approved/paid/reversed)
GET /api/reseller/referral/payouts # ödeme talepleri/geçmişi
POST /api/reseller/referral/payouts # multipart: invoice=@fatura.pdf VEYA issue_einvoice=true
GET /api/reseller/referral/payouts/{id}/invoice # yüklenen faturayı indir (binary)
Sözleşme eksikse tek adımda katılım:
POST /api/reseller/referral/opt-in
{
"accepted": true,
"acknowledged_sha256": "<data.agreement.sha256>",
"accept_reseller_bundle": true,
"bundle_acknowledged_hashes": {
"reseller-agreement": "<sha>", "reseller-mesafeli": "<sha>", "reseller-dpa": "<sha>"
}
}
Hash'ler
GET /api/reseller/referralyanıtındakidata.agreement.sha256vedata.reseller_bundle[].sha256alanlarından gelir. Metin bu arada güncellenmişse409 stale_documentalırsın → yeniden oku, yeni hash'le gönder.
Gizli satış paketi (partner paketi): Paket hiçbir fiyat listesinde görünmez; satış yalnız
POST yanıtındaki data.sale_url (https://dowaba.com/paket/{uuid}) ile açılır. Müşteri o
sayfadan önce öder, sonra şifresini belirler; dowaba'nın OWNER müşterisi olur (fatura
dowaba'dan). Kota/fiyat/site/modül oluşturulduktan sonra değiştirilemez — değişiklik için yeni
paket açıp eskisini is_active:false yap.
Taban fiyat (422 yemeden önce hesapla):
aylık taban = mesaj × 0,20₺ + çağrı × 0,20₺ + (site − 1) × 150₺, dönem tabanı = aylık taban ×
çarpan (monthly 1 · quarterly 3 · semiannual 5 · yearly 10). Örn. 1.000 mesaj + 100 çağrı +
1 site → aylık 220₺, yıllık 2.200₺. Katsayılar GET .../packages → data.limits.
Ödeme talebi: kısmi tutar YOK — birikmiş tüm hakediş tek talepte toplanır. Ön koşullar: IBAN
kayıtlı + eşik (data.min_payout_try, varsayılan 500₺) aşılmış + açık talep yok + fatura
(dosya veya kendi Nilvera hesabından issue_einvoice=true).
⚠️ Müşteri verisi sınırı:
customersucu yalnız ad + tarih + abonelik durumu döner. E-posta/telefon/site/konuşma bilinçli olarak yoktur ve bunları veren başka bir uç da yok (bayi müşterisi ≠ referans müşterisi). Tam alan listesi: API Dokümantasyonu → "Bayi — Referans Programı".
Onaylı bayi demo modülleri kataloğu (tüm kullanıcılar) + bayi ilan yönetimi (role=reseller
ve aktif ödenmiş abonelik — yazma uçları abonelik pasifken 403 subscription_required):
GET /api/custom-integrations # katalog (approved + published)
GET /api/custom-integrations/{slug} # detay (galeri + demo erişimi)
GET /api/reseller/custom-integrations # kendi ilanların + can_manage + limits
POST /api/reseller/custom-integrations { "title", "short_description", "description", "demo_url", "price"?, "gallery_media_ids"?[] }
PUT /api/reseller/custom-integrations/{id} # onaylı ilanda içerik değişirse yeniden onaya düşer
POST /api/reseller/custom-integrations/{id}/submit # taslağı onaya gönder
PATCH /api/reseller/custom-integrations/{id}/publish { "is_published": true } # yalnız approved
GET/POST /api/reseller/custom-integrations/{id}/faqs # SSS önerileri (onaylanınca dowaba.com SSS'ine eklenir)
DELETE /api/reseller/custom-integration-faqs/{id} # yalnız pending/rejected öneri
Görseller mevcut
POST /api/media/uploadile yüklenir;gallery_media_idsen fazla 20, yalnız kendi medya havuzundan. Yayın kararı superadmin onayına bağlıdır (durumlar:draft → pending → approved/rejected).
*/send, mail/reply) idempotent değildir —
aynı isteği iki kez atarsan iki mesaj gider. Kendi tarafında dedup uygula.toggle-bot ile o konuşmada botu kapat.profile_id (hangi bağlı numara/hesap) bekler.
inbox/unified ve {kanal}/conversations yanıtlarında gelir; mesaj/gönder isteğinde geri ver.issues_sanctum_token için aydin@dowaba.com.Sürüm notları artık panelde (dinamik, sürümlü): Geliştirici → Sürüm Notları sekmesi (
/admin/developer). Her deploy otomatik bir taslak üretir (eklenen/çıkan endpoint + git değişiklikleri); ekip bunu geliştirici-dostu dille düzenleyip yayınlar. Geçmiş ve yeni tüm API değişikliklerini oradan takip et — eski statik liste kaldırıldı (her sürümde elle güncellenmiyordu, geride kalıyordu).
Bunlara güvenebilirsin — kırıcı değişiklik olursa burada duyurulur:
sanctum_token TTL'siz — yalnız oauth/revoke veya refresh rotation ile silinir (§ 0.2).*/send, mail/reply, send-template) idempotent değildir — kendi tarafında dedup uygula.{success,data} / kök array / {data,total}) — ilk çağrıda şekli doğrula (§ 0.4).