Geliştirici
Messaging API v1
WhatsApp, Instagram, X ve website sohbetlerini sunucunuzdan okuyun ve yanıtlayın. WhatsApp’ta 24 saat dışında onaylı şablon zorunludur. Anahtar düz metin saklanmaz; her istek HMAC-SHA256 ile imzalanır.
Temel URL
https://www.aidiance.com/api/v1/{resource}
JSON. CORS yok (tarayıcıya anahtar koymayın). Yalnızca HTTPS. Anahtarları panelden oluşturun: Ayarlar → Entegrasyon.
Kimlik doğrulama
Her istekte dört başlık zorunludur:
| Başlık | Açıklama |
|---|---|
Authorization | Bearer aid_live_… — panelde bir kez gösterilir, sunucuda yalnızca HMAC karması tutulur. |
X-Aidiance-Timestamp | Unix saniye (UTC). ±5 dakika pencere. |
X-Aidiance-Nonce | 16–64 hex karakter, anahtar başına tek kullanımlık (replay koruması). |
X-Aidiance-Signature | Aşağıdaki kanonik metnin HMAC-SHA256 (hex) değeri. |
X-Aidiance-Idempotency-Key | İsteğe bağlı (POST gönderim). 24 saat aynı yanıtı döndürür; çift mesajı önler. |
Yetkiler (scope): conversations.read, messages.read, messages.send, webhooks.manage (REST hooks), inbox.embed (gömülü konuşmalar). Anahtar isteğe bağlı IP allowlist ve asistan kısıtı ile üretilir.
İmza algoritması
UTF-8, satır sonu \n:
timestamp nonce METHOD resource canonicalQuery sha256hex(body)
METHODbüyük harf, isteğin gerçek yöntemi:GET/POST(silme deX-HTTP-Method-Override: DELETEbaşlıklıPOSTile yapılır vePOSTolarak imzalanır)resourceküçük harf,/api/v1/sonrasındaki yol:messages,conversations,webhooks,webhooks/42, …canonicalQuery:resourcehariç sorgu parametreleri, anahtara göre sıralıkey=urlencode(value). POST’ta boş satır.bodyham baytlar (GET’te boş; SHA-256 boş gövde =e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)
İmza: HMAC-SHA256(api_key, payload) küçük harf hex. Gönderilen JSON ile hash’lenen gövde birebir aynı olmalıdır.
Konuşma kimliği
| Kanal | conversation_id |
|---|---|
wa:{asistan_token}:{telefon} — telefon ülke kodu ile, yalnızca rakam | |
ig:{asistan_token}:{participant_id} | |
x:{asistan_token}:{participant_id} | |
| web | web:{grpid} |
Liste uçundan gelen id alanını olduğu gibi kullanın. WhatsApp 24 saatlik oturum penceresi Meta kurallarına tabidir.
Uçlar
GET/api/v1/me
Anahtar adı, scope ve kanal özeti. Gövde yok.
GET/api/v1/assistants
Hesaba (ve anahtar kısıtına) ait asistanlar. Scope: conversations.read veya messages.read.
GET/api/v1/conversations
Sorgu: channel (whatsapp | instagram | twitter | web, boş = izinli hepsi), limit (1–50).
{
"ok": true,
"items": [
{
"id": "wa:TOKEN:905551112233",
"channel": "whatsapp",
"assistant_token": "TOKEN",
"assistant_name": "Satış",
"contact": "Ayşe",
"handle": "905551112233",
"last_message": "Merhaba",
"last_at": "2026-09-10T16:01:00"
}
]
}
GET/api/v1/messages
Sorgu: conversation_id (zorunlu), since_id (dahil değil, polling), limit (1–50).
{
"ok": true,
"items": [
{
"id": 1201,
"provider_id": "wamid....",
"direction": "inbound",
"type": "text",
"text": "Fiyat nedir?",
"status": "",
"created_at": "2026-09-10T16:00:12"
}
]
}
Yeni mesaj için son gördüğünüz id ile since_id gönderin (en fazla birkaç saniyede bir; rate limit).
POST/api/v1/messages
{
"conversation_id": "wa:TOKEN:905551112233",
"text": "Merhaba, nasıl yardımcı olabilirim?"
}
veya:
{
"channel": "whatsapp",
"assistant_token": "TOKEN",
"to": "905551112233",
"text": "Merhaba"
}
Başarılı: ok, message_id, conversation_id. Metin en fazla 4096 karakter. WhatsApp’ta 24 saatlik müşteri penceresi kapandıysa serbest metin gitmez; aşağıda şablon gönderimi kullanın.
WhatsApp şablonları (yeni sohbet / 24 saat dışı)
Meta kuralı: müşteri son 24 saatte yazmadıysa yalnızca onaylı mesaj şablonu gönderilebilir. Şablonları panelde oluşturup Meta onayından geçirin; API yalnızca onaylı olanları listeler ve gönderir.
GET/api/v1/templates
Sorgu: assistant_token (zorunlu). Scope: messages.read veya messages.send.
{
"ok": true,
"items": [
{
"name": "karsilama",
"language": "tr",
"category": "UTILITY",
"status": "APPROVED",
"body_text": "Merhaba {{1}}, size nasıl yardımcı olabiliriz?",
"body_variable_count": 1,
"header_format": "TEXT",
"header_variable_count": 0,
"footer_text": ""
}
]
}
POST/api/v1/messages (şablon)
text yerine template gönderin. Scope: messages.send. Aynı HMAC ve isteğe bağlı X-Aidiance-Idempotency-Key.
{
"channel": "whatsapp",
"assistant_token": "TOKEN",
"to": "905551112233",
"template": {
"name": "karsilama",
"language": "tr",
"body_variables": ["Ayşe"],
"header_variables": [],
"header_media_url": "",
"url_button_suffixes": []
}
}
Mevcut konuşma için conversation_id da kullanılabilir:
{
"conversation_id": "wa:TOKEN:905551112233",
"template": {
"name": "karsilama",
"language": "tr",
"body_variables": ["Ayşe"]
}
}
body_variables: gövdedeki {{1}}, {{2}}, … sırasıyla. Sayı şablondakibody_variable_countile aynı olmalı.header_variables: üst bilgi metin değişkenleri (varsa).header_media_url: başlık IMAGE/VIDEO/DOCUMENT ise herkese açık HTTPS URL (Meta dosyayı çeker).url_button_suffixes: dinamik URL butonlarındaki {{1}} parçaları (varsa).
Başarılı yanıt: ok, message_id, conversation_id, template, language.
Kişi DUR / İPTAL yazarak pazarlama mesajlarından çıktıysa pazarlama (MARKETING) ya da kategorisi belirlenemeyen şablonlar gönderilmez ve 403 opted_out döner; hizmet (UTILITY) ve doğrulama (AUTHENTICATION) şablonları gönderilebilir.
Webhook'lar (giden olaylar)
Seçtiğiniz olaylar gerçekleştiğinde Aidiance, verdiğiniz HTTPS adresine JSON gövdeyle POST isteği gönderir. Webhook'ları panelde Ayarlar → Webhook & API sayfasından veya REST hooks uçlarıyla yönetin. Her webhook'un kendine ait bir gizli anahtarı (whsec_…) vardır.
POST https://sunucunuz.com/aidiance/webhook Content-Type: application/json; charset=utf-8 User-Agent: Aidiance-Webhook/1.0 X-Aidiance-Event: message.received X-Aidiance-Delivery: 18342 X-Aidiance-Timestamp: 1791043200 X-Aidiance-Signature: sha256=5f1c9e…
| Başlık | Açıklama |
|---|---|
X-Aidiance-Event | Olay adı (ör. message.received; panelden test gönderiminde test). |
X-Aidiance-Delivery | Teslim numarası; aynı teslimin yeniden denemelerinde değişmez. |
X-Aidiance-Timestamp | İsteğin imzalandığı an, Unix saniye (UTC); her denemede yenilenir. |
X-Aidiance-Signature | sha256= + HMAC-SHA256(gizli anahtar, timestamp + "." + ham gövde), küçük harf hex. |
Gövde
{
"id": "9b2f6c1e-5d4a-4a8e-9f0b-3c7d2e1a6b54",
"olay": "message.received",
"zaman": "2026-10-03T14:05:00+03:00",
"veri": { … }
}
id: olay kimliği. Yeniden denemelerde ve aynı olayın farklı webhook'lara teslimlerinde aynıdır; tekrarları bununla ayıklayın.zaman: olayın oluştuğu an (ISO 8601, saat dilimi ofsetli).veri: olaya özel alanlar. Yeni alanlar eklenebilir; tanımadığınız alanları yok sayın.- Panelden test gönderiminde gövdeye
"test": trueve"ornek_olay"eklenir;veriseçilen olayın örnek verisidir.
Olaylar ve örnek yükler
| Olay | Ne zaman? |
|---|---|
| message.received | Müşteriden WhatsApp, Instagram (DM ve yorum), Messenger, X veya web sohbetinden yeni mesaj geldiğinde. |
| message.sent | Panelden, AI'dan, otomatik kuraldan, şablondan, zamanlamadan, mobil uygulamadan veya API'den mesaj gönderildiğinde. |
| message.status | Giden mesaj iletildi (delivered), okundu (read) veya başarısız oldu (failed). |
| conversation.assigned | Konuşma bir ekip üyesine atandığında. |
| conversation.status_changed | Konuşma açık, beklemede veya kapalı olarak işaretlendiğinde (süre dolunca otomatik kapatma dahil). |
| conversation.handoff | AI asistan konuşmayı insan desteğine devrettiğinde. |
| lead.created | AI asistan WhatsApp sohbetinden iletişim bilgisi (lead) yakalayıp Formlar'a kaydettiğinde. |
| order.reminder_sent | E-ticaret entegrasyonu terk edilen sepet veya ödenmemiş sipariş için WhatsApp hatırlatması gönderdiğinde. |
| review.received | Google İşletme profilinize yeni bir değerlendirme geldiğinde. |
Mesaj olaylarındaki konusma_id, POST /api/v1/messages isteğindeki conversation_id ile aynı biçimdedir; desteklenen kanallarda gelen mesaja doğrudan yanıt verebilirsiniz. Aşağıdaki yükler örnektir; alanlar olayı üreten modüle göre genişleyebilir.
message.received
{
"id": "9b2f6c1e-5d4a-4a8e-9f0b-3c7d2e1a6b54",
"olay": "message.received",
"zaman": "2026-10-03T14:05:00+03:00",
"veri": {
"kanal": "whatsapp",
"asistan_token": "TOKEN",
"asistan_adi": "Satış Asistanı",
"konusma_anahtari": "905551112233",
"konusma_id": "wa:TOKEN:905551112233",
"kisi_adi": "Ayşe Yılmaz",
"mesaj_id": "wamid.HBgM…",
"tip": "text",
"metin": "Merhaba, siparişim ne zaman kargoya verilir?",
"yon": "gelen",
"kaynak": "musteri",
"mesaj_zamani": "2026-10-03T14:05:00+03:00"
}
}
kanal: whatsapp, instagram, instagram_yorum, messenger, x, web. Medya mesajlarında medya_id, medya_url (varsa) ve mime alanları da gelir.
message.sent
"veri": {
"kanal": "instagram",
"asistan_token": "TOKEN",
"asistan_adi": "Satış Asistanı",
"konusma_anahtari": "17841400000000000",
"konusma_id": "ig:TOKEN:17841400000000000",
"kisi_adi": null,
"mesaj_id": "aWdfZAG1…",
"tip": "text",
"metin": "Siparişiniz bugün kargoya verilecek.",
"yon": "giden",
"kaynak": "ai",
"gonderen_kullanici_id": 0,
"mesaj_zamani": "2026-10-03T14:05:04+03:00"
}
kaynak: panel, ai, otomatik, sablon, zamanlama, api, mobil, harici (kanalın kendi uygulamasından gönderilen). gonderen_kullanici_id panel ve mobil gönderimlerinde ekip üyesinin kimliğidir, diğerlerinde 0.
message.status
"veri": {
"kanal": "whatsapp",
"asistan_token": "TOKEN",
"asistan_adi": "Satış Asistanı",
"konusma_anahtari": "905551112233",
"konusma_id": "wa:TOKEN:905551112233",
"mesaj_id": "wamid.HBgM…",
"durum": "read",
"durum_zamani": "2026-10-03T14:06:10+03:00"
}
conversation.assigned
"veri": {
"kanal": "whatsapp",
"asistan": "TOKEN",
"anahtar": "905551112233",
"atanan_id": 42,
"atanan_ad": "Mehmet Kaya",
"atayan_id": 31,
"otomatik": false,
"zaman": "2026-10-03T14:05:00+03:00",
"asistan_adi": "Satış Asistanı",
"konusma_id": "wa:TOKEN:905551112233"
}
asistan asistan token'ı, anahtar konuşma anahtarıdır (WhatsApp'ta telefon). Otomatik atamada otomatik = true ve atayan_id = 0.
conversation.status_changed
"veri": {
"kanal": "whatsapp",
"asistan": "TOKEN",
"anahtar": "905551112233",
"durum": "kapali",
"eski_durum": "acik",
"degistiren_id": 31,
"otomatik": false,
"zaman": "2026-10-03T14:05:00+03:00",
"asistan_adi": "Satış Asistanı",
"konusma_id": "wa:TOKEN:905551112233"
}
durum: acik, beklemede, kapali. Süre dolunca otomatik kapatmada otomatik = true ve degistiren_id = 0.
conversation.handoff
"veri": {
"kanal": "instagram",
"asistan": "TOKEN",
"anahtar": "17841400000000000",
"neden": "Müşteri canlı destek istedi.",
"atanan_id": 42,
"zaman": "2026-10-03T14:05:00+03:00",
"asistan_adi": "Satış Asistanı",
"konusma_id": "ig:TOKEN:17841400000000000"
}
AI konuşmayı insan desteğine devrettiğinde gelir; otomatik atama yapılamadıysa atanan_id = 0.
lead.created
"veri": {
"channel": "whatsapp",
"assistant": "TOKEN",
"conversation_key": "905551112233",
"form_id": 1287,
"fields": {
"Ad Soyad": "Ayşe Yılmaz",
"E-posta": "ayse@example.com",
"Firma": "Yılmaz Tekstil",
"Kaynak": "WhatsApp",
"WhatsApp numarası": "905551112233"
},
"created_at": "2026-10-03T14:05:00+03:00",
"assistant_name": "Satış Asistanı",
"conversation_id": "wa:TOKEN:905551112233"
}
fields yalnızca dolu alanları içerir: Ad Soyad, E-posta, Telefon, Firma, Not; her zaman Kaynak ve WhatsApp numarası. form_id paneldeki Formlar kaydının numarasıdır.
order.reminder_sent
"veri": {
"magaza_id": 3,
"magaza": "Örnek Mağaza",
"platform": "shopify",
"sepet_id": 981,
"tur": "sepet",
"platform_ref": "c1-7f3a9e",
"musteri": "Ayşe Yılmaz",
"telefon": "905551112233",
"eposta": "ayse@example.com",
"toplam": 1249.9,
"para_birimi": "TRY",
"baglanti": "https://ornekmagaza.com/cart/c1-7f3a9e",
"sablon": "sepet_hatirlatma",
"mesaj_id": "wamid.HBgM…",
"zaman": "2026-10-03T14:05:00+03:00"
}
tur: sepet (terk edilen sepet) veya siparis (ödenmemiş sipariş). platform: shopify, woocommerce, ikas, ideasoft, ticimax. Gönderilen WhatsApp şablonu ayrıca message.sent olayı (kaynak otomatik) olarak da gelir.
review.received
"veri": {
"channel": "google",
"assistant": "TOKEN",
"review_id": 512,
"google_review_name": "accounts/…/locations/…/reviews/…",
"location": "Örnek Mağaza Kadıköy",
"rating": 5,
"comment": "Çok hızlı ve ilgili bir hizmet aldım.",
"reviewer": "Ali Demir",
"review_time": "2026-10-03T13:58:00+03:00",
"has_reply": false,
"assistant_name": "Satış Asistanı"
}
lead.created ve review.received olaylarında İngilizce anahtarlar. Aidiance bu olaylara asistan adını (asistan_adi / assistant_name) ve API ile yanıt vermek için kullanılabilecek konuşma kimliğini (konusma_id / conversation_id; WhatsApp, Instagram, X ve web için) ekler. Tüm zamanlar 2026-10-03T14:05:00+03:00 biçimindedir. Yeni alanlar eklenebilir; bilinmeyen alanları yok sayın.Webhook imzasını doğrulama
- İsteğin ham gövdesini okuyun; JSON'u ayrıştırıp yeniden serileştirmeyin.
imzalanan = X-Aidiance-Timestamp + "." + ham gövde(UTF-8).beklenen = "sha256=" + hex(HMAC-SHA256(gizli anahtar, imzalanan))(küçük harf).X-Aidiance-Signatureile sabit zamanlı karşılaştırın; zaman damgası 5 dakikadan eskiyse isteği reddedin.
const crypto = require('crypto');
const express = require('express');
const app = express();
app.post('/aidiance/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const zaman = req.get('X-Aidiance-Timestamp') || '';
const imza = req.get('X-Aidiance-Signature') || '';
const govde = req.body.toString('utf8');
const beklenen = 'sha256=' + crypto
.createHmac('sha256', process.env.AIDIANCE_WEBHOOK_SECRET)
.update(zaman + '.' + govde)
.digest('hex');
const gecerli = imza.length === beklenen.length &&
crypto.timingSafeEqual(Buffer.from(imza), Buffer.from(beklenen));
if (!gecerli || Math.abs(Date.now() / 1000 - Number(zaman)) > 300) return res.sendStatus(401);
const olay = JSON.parse(govde); // olay.id ile tekrarları ayıklayın
console.log(olay.olay, olay.veri);
res.sendStatus(200);
});<?php
$gizli = getenv('AIDIANCE_WEBHOOK_SECRET');
$govde = file_get_contents('php://input'); // ham gövde
$zaman = $_SERVER['HTTP_X_AIDIANCE_TIMESTAMP'] ?? '';
$imza = $_SERVER['HTTP_X_AIDIANCE_SIGNATURE'] ?? '';
$beklenen = 'sha256=' . hash_hmac('sha256', $zaman . '.' . $govde, $gizli);
if (!hash_equals($beklenen, $imza) || abs(time() - (int)$zaman) > 300) {
http_response_code(401);
exit;
}
$olay = json_decode($govde, true); // $olay['id'] ile tekrarları ayıklayın
http_response_code(200);import hashlib, hmac, os, time
from flask import Flask, request, abort
app = Flask(__name__)
GIZLI = os.environ["AIDIANCE_WEBHOOK_SECRET"].encode("utf-8")
@app.post("/aidiance/webhook")
def aidiance_webhook():
zaman = request.headers.get("X-Aidiance-Timestamp", "")
imza = request.headers.get("X-Aidiance-Signature", "")
govde = request.get_data() # ham bayt
beklenen = "sha256=" + hmac.new(GIZLI, zaman.encode() + b"." + govde, hashlib.sha256).hexdigest()
if not hmac.compare_digest(beklenen, imza) or not zaman.isdigit() or abs(time.time() - int(zaman)) > 300:
abort(401)
olay = request.get_json() # olay["id"] ile tekrarları ayıklayın
return "", 200// ASP.NET Core (minimal API)
using System.Security.Cryptography;
using System.Text;
app.MapPost("/aidiance/webhook", async (HttpRequest req) =>
{
using var okuyucu = new StreamReader(req.Body, Encoding.UTF8);
var govde = await okuyucu.ReadToEndAsync(); // ham gövde
var zaman = req.Headers["X-Aidiance-Timestamp"].ToString();
var imza = req.Headers["X-Aidiance-Signature"].ToString();
var gizli = Environment.GetEnvironmentVariable("AIDIANCE_WEBHOOK_SECRET")!;
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(gizli));
var beklenen = "sha256=" + Convert.ToHexString(
hmac.ComputeHash(Encoding.UTF8.GetBytes(zaman + "." + govde))).ToLowerInvariant();
var gecerli = CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(beklenen), Encoding.UTF8.GetBytes(imza));
if (!gecerli || !long.TryParse(zaman, out var ts)
|| Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - ts) > 300)
return Results.Unauthorized();
return Results.Ok();
});Teslim ve yeniden deneme
- Alıcı 10 saniye içinde
2xxdöndürürse teslim başarılı sayılır; yönlendirmeler (3xx) izlenmez. - Başarısız teslimler 1 dk, 5 dk, 30 dk, 2 sa ve 6 sa sonra yeniden denenir (en fazla 6 deneme, toplam ~8,5 saat).
410 Goneyanıtı aboneliği sonlandırır: webhook kapatılır, bekleyen teslimler iptal edilir.- Art arda 50 deneme başarısız olur ve 24 saat boyunca hiç başarılı teslim yapılamazsa webhook otomatik kapatılır; hesap sahibine panel bildirimi gönderilir.
- Teslim en az bir kez garantilidir, sıra garanti edilmez: gövdedeki
idile tekrarları ayıklayın, uzun süren işleri kendi kuyruğunuza alın. - Yalnızca herkese açık
https://adresleri kabul edilir. Teslim kayıtları panelde 30 gün görüntülenir ve tek tıkla yeniden gönderilebilir.
REST hooks: webhook'ları API ile yönetme
Zapier veya Make için kendi uygulamanızı geliştiriyorsanız abonelikleri programatik olarak açıp kapatabilirsiniz. Scope: webhooks.manage (anahtarı oluştururken seçin). Webhook'lar hesap genelindeki olayları aldığından asistana kısıtlı anahtarlarla oluşturulamaz; özellik paketinize dahil olmalıdır.
GET/api/v1/webhooks
{
"ok": true,
"items": [
{
"id": 42,
"name": "Zapier — CRM",
"url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
"events": ["message.received", "lead.created"],
"active": true,
"source": "api",
"created_at": "2026-10-03T14:00:00",
"last_success_at": "2026-10-03T14:05:01",
"consecutive_failures": 0
}
]
}
POST/api/v1/webhooks
{
"url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
"events": ["message.received", "lead.created"],
"name": "Zapier — CRM"
}
events dizi, virgüllü metin veya tüm olaylar için "*" olabilir; url yerine target_url veya hookUrl da kabul edilir. Başarılı yanıt 201:
{
"ok": true,
"id": 42,
"name": "Zapier — CRM",
"url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
"events": ["message.received", "lead.created"],
"active": true,
"secret": "whsec_…"
}
secret yalnızca bu yanıtta döner; imza doğrulaması için saklayın (panelden de görüntülenebilir veya yenilenebilir).
url ve aynı olaylarla tekrar gönderilen istek yeni kayıt açmaz: mevcut webhook 200 ile döner (aynı id ve secret, "existing": true; kapatılmışsa yeniden açılır). Bu nedenle Zapier/Make subscribe adımında zaman aşımından sonra isteği güvenle yineleyebilirsiniz. Adres panelden, başka bir anahtarla ya da farklı olaylarla zaten kayıtlıysa 409 duplicate_webhook döner (mesajda mevcut kaydın id'si yer alır). Aynı hesapta eşzamanlı başka bir webhook işlemi sürüyorsa 409 busy döner; birkaç saniye sonra yineleyin.GET/api/v1/webhooks/{id}
Tek webhook: { "ok": true, "item": { … } }. Eşdeğeri: GET /api/v1/webhooks?id=42.
POST/api/v1/webhooks/{id} + X-HTTP-Method-Override: DELETE
Webhook'u siler. İsteği POST olarak gönderip X-HTTP-Method-Override: DELETE başlığını ekleyin; gövde boş olabilir. Eşdeğeri: POST /api/v1/webhooks?id=42 + aynı başlık.
POST /api/v1/webhooks/42
X-HTTP-Method-Override: DELETE
{ "ok": true, "deleted": true, "id": 42 }
POST); resource, /api/v1/ sonrasındaki yoldur (webhooks/42, ya da ?id= biçiminde webhooks ve canonicalQuery = id=42). Sunucu yapılandırması gerçek DELETE isteklerini engelleyebileceğinden bu yöntemi kullanın. Olmayan kimlik 404 not_found döner.Zapier REST hook eşlemesi
- Subscribe:
POST /api/v1/webhooks, gövde{"url": "{{bundle.targetUrl}}", "events": ["message.received"]}; dönenid'yi saklayın. - Unsubscribe:
POST /api/v1/webhooks/{{bundle.subscribeData.id}}, başlıkX-HTTP-Method-Override: DELETE. - Perform: gelen gövde
bundle.cleanedRequest; alanlarverialtındadır. - Zap kapatıldığında hook adresi
410döndürürse webhook burada da otomatik kapanır.
Zapier ve Make ile kodsuz kurulum
Zapier — Webhooks by Zapier
- Yeni bir Zap oluşturun; tetikleyici: Webhooks by Zapier → Catch Hook.
- Zapier'in verdiği
https://hooks.zapier.com/hooks/catch/…adresini kopyalayın. - Panelde Webhook & API → Webhook ekle: adresi yapıştırın ve olayları seçin.
- Test gönder ile örnek bir olay yollayın; Zapier'de Test trigger deyin.
- Eylem adımlarında
veri__metin,veri__kisi_adi,veri__konusma_idgibi alanları kullanın.
Make — Custom webhook
- Yeni senaryo oluşturun; ilk modül: Webhooks → Custom webhook → Add.
- Verilen
https://hook.eu1.make.com/…adresini kopyalayıp panelde webhook olarak ekleyin. - Make modülü veri beklerken panelde Test gönder'e basın; veri yapısı otomatik algılanır.
- Sonraki modüllerde
verialanlarını eşleyin ve senaryoyu açın.
Zapier ve Make hook adresleri gizli tutulmalıdır. Kendi sunucunuzda mutlaka imzayı doğrulayın.
Gömülü konuşmalar (iframe)
Panelin Konuşmalar ekranını kendi sitenizde (ör. yönetim sayfanızda) gösterin. Pencerede o kişi için yalnız Konuşmalar ekranını gören kısıtlı bir oturum açılır (ayarlar, API anahtarları, paket ve güvenlik ekranları bu oturuma kapalıdır). İki yol vardır: sunucu kodu gerektirmeyen tek satırlık kod ya da sunucunuzdan otomatik giriş.
Kolay yöntem: tek satır kod + “Aidiance ile bağlan”
- Panel › Entegrasyon › Konuşmaları sitenize gömün kartında izinli siteleri (yalnız https) yazıp açın ve kaydedin (yalnız ana hesap). Kartta hesabınızın koduyla hazır iframe ve script kodları çıkar.
- Kodlardan birini sitenizde Konuşmaların görüneceği sayfaya yapıştırın:
<iframe src="https://www.aidiance.com/gomulu_giris.aspx?h=HESAP_KODU" style="width:100%;height:720px;border:0" title="Konuşmalar" referrerpolicy="origin" allow="clipboard-write"></iframe>
<script src="https://www.aidiance.com/assets/js/gomulu-konusmalar.js" data-hesap="HESAP_KODU" async></script>
- Script, pencereyi kodun bulunduğu yere ekler ve yüksekliğini ekrana göre ayarlar. İsteğe bağlı:
data-hedef="#kutu"(pencerenin konacağı öğe),data-yukseklik="720px"(sabit yükseklik). - Ekipteki her kişi pencerede bir kez Aidiance ile bağlan’a basar. Açılan Aidiance penceresinde (oturum yoksa giriş; iki adımlı doğrulama dahil) hangi hesapla bağlanacağını görüp Bağlan’ı onaylar. Bağlantı o tarayıcıda, yalnız o sitenin penceresinde 30 gün açık kalır; süre dolunca pencere yeniden bağlanmayı ister.
- Bağlanan kişi bu hesabın ana kullanıcısı ya da Konuşmalar yetkili bir ekip üyesi (alt kullanıcı) olmalıdır; herkes kendi yetkileriyle görür. Başka bir Aidiance hesabıyla bağlanılamaz.
- Hesap kodu gizli değildir ve tek başına erişim vermez: pencere yalnız izinli sitelerde çerçevelenir, bağlanma Aidiance’ın kendi penceresinde yapılır ve şifre sitenize yazılmaz.
- Bağlantılar Güvenlik › Aktif oturumlar’da Gömülü konuşmalar (Aidiance ile bağlan) olarak görünür ve oradan kapatılabilir. Özelliği kapatmak ya da siteyi listeden çıkarmak tüm bağlantıları hemen sonlandırır.
- Tarayıcı gömülü pencerede oturuma izin vermezse (ör. Safari’nin bazı sürümleri) pencerede Konuşmaları yeni sekmede aç düğmesi çıkar ve Konuşmalar normal Aidiance panelinde açılır. Açılır pencere engellenirse tarayıcıda o siteye açılır pencere izni verin.
Gelişmiş: sunucudan otomatik giriş (API)
Sitenize giriş yapmış kişi için Konuşmaları “bağlan” adımı olmadan açmak isterseniz sunucunuz, sayfayı açan kişi için tek kullanımlık bir bağlantı alır ve iframe’e koyar; ekibiniz ayrıca Aidiance şifresi girmez.
- Panel › Entegrasyon’da
inbox.embed(Gömülü konuşmalar) yetkili, asistana kısıtlanmamış ve tüm kanallara açık bir anahtar oluşturun (bu anahtarı ve gömme ayarını yalnız ana hesap yönetir). - Aynı sayfadaki Konuşmaları sitenize gömün kartında izinli siteleri (yalnız https) yazıp açın. Konuşmalar yalnız bu sitelerde çerçevelenebilir.
- Sayfanız her açıldığında sunucunuz aşağıdaki ucu çağırıp dönen
url’i iframe’e koyar.
POST/api/v1/embed_sessions
| Alan | Açıklama |
|---|---|
email | İsteğe bağlı. Giriş yapılacak kullanıcının Aidiance e-postası: ana hesap ya da ekip üyesi (alt kullanıcı). Ekip üyesi kendi yetkileriyle görür; Konuşmalar yetkisi olmalıdır. Boşsa ana hesap. |
site | İframe’in açılacağı sitenin kökeni (https://yonetim.siteniz.com). Tek izinli site varsa gerekmez. |
HTTP 201
{
"ok": true,
"url": "https://www.aidiance.com/gomulu_giris.aspx?t=gk_…",
"expires_in": 300,
"expires_at": "2026-10-04T12:00:00Z",
"site": "https://yonetim.siteniz.com",
"user": "temsilci@firma.com"
}
<iframe src="{url}" style="width:100%;height:720px;border:0" title="Konuşmalar"></iframe>
- Bağlantı tek kullanımlıktır ve
expires_insaniye içinde açılmalıdır; her sayfa açılışında yenisini alın, bağlantıyı önbelleğe almayın ya da paylaşmayın. - İmza diğer uçlarla aynıdır:
resource=embed_sessions,canonicalQueryboş, gövde gönderdiğiniz JSON’un ham baytları. - Oturum çerezi tarayıcının bölümlenmiş çerez desteğiyle (CHIPS) yalnız o sitenin iframe’inde tutulur; tarayıcıdaki Aidiance oturumuna dokunmaz. Tarayıcı izin vermezse (ör. Safari’nin bazı sürümleri) pencerede Yeni sekmede aç düğmesi çıkar; yeni sekmede hangi hesapla açılacağı gösterilir ve kullanıcı onaylayınca açılır.
- Gömülü oturum en çok 12 saat sürer. Süre dolunca (ya da oturum başka bir nedenle bitince) iframe, sayfanıza
{ aidiance: "oturum_sona_erdi" }mesajınıpostMessageile gönderir; dinleyip sayfayı yenilerseniz yeni bağlantı alınır (mesajınorigin’ini denetleyin; döngüye girmemek için yalnız sayfa en az bir dakikadır açıksa yenileyin). - Panelde özelliği kapatmak, bir siteyi listeden çıkarmak ya da
inbox.embedyetkili anahtarı iptal etmek bu yolla açılmış gömülü oturumları hemen sonlandırır; iptal edilen anahtarla alınmış bağlantılar da açılmaz (anahtar iptali “Aidiance ile bağlan” bağlantılarını etkilemez).
| HTTP | error | |
|---|---|---|
| 400 | site_required / site_not_allowed | Birden çok izinli site varken site yok / site listede değil |
| 403 | insufficient_scope / key_restricted / embed_disabled / feature_unavailable | Anahtarda inbox.embed yok / anahtar asistana ya da kanala kısıtlı / özellik kapalı / paket |
| 403 | user_inactive / forbidden | Kullanıcı pasif / ekip üyesinin Konuşmalar yetkisi yok |
| 404 / 409 | user_not_found / ambiguous_user | E-posta hesabınızda bulunamadı / birden çok kullanıcıda kayıtlı |
PHP örneği
$key = getenv('AIDIANCE_API_KEY'); // inbox.embed yetkili anahtar (yalnız sunucuda)
$body = json_encode(['email' => $kullaniciEposta, 'site' => 'https://yonetim.siteniz.com']);
$ts = (string) time();
$nonce = bin2hex(random_bytes(16));
$imza = hash_hmac('sha256', $ts . "\n" . $nonce . "\nPOST\nembed_sessions\n\n" . hash('sha256', $body), $key);
$ch = curl_init('https://www.aidiance.com/api/v1/embed_sessions');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $key,
'X-Aidiance-Timestamp: ' . $ts, 'X-Aidiance-Nonce: ' . $nonce, 'X-Aidiance-Signature: ' . $imza],
]);
$url = json_decode(curl_exec($ch), true)['url']; // <iframe src="...">
Hatalar
{
"ok": false,
"error": "bad_signature",
"message": "İmza doğrulanamadı.",
"request_id": "…"
}
| HTTP | error | |
|---|---|---|
| 400 | bad_request / invalid_json / invalid_url / invalid_events | Geçersiz istek |
| 401 | auth_required / invalid_key / bad_signature / replay | Kimlik veya imza |
| 403 | https_required / ip_denied / insufficient_scope / forbidden / feature_unavailable / limit_reached / key_restricted | Yetki, paket veya limit |
| 403 | opted_out | Kişi DUR / İPTAL yazarak pazarlama mesajlarından çıktı; pazarlama (MARKETING) ya da kategorisi bilinmeyen şablon gönderilmez. Hizmet (UTILITY) ve doğrulama (AUTHENTICATION) şablonları gönderilebilir. |
| 404 / 405 | not_found / method_not_allowed | Uç veya kayıt bulunamadı |
| 409 | duplicate_webhook / busy / ambiguous_user | Aynı adrese ikinci webhook / eşzamanlı işlem / e-posta birden çok kullanıcıda |
| 429 | rate_limited / auth_locked | Hız limiti |
| 502 | provider_error | WhatsApp / Meta / X |
Python örneği
import hashlib, hmac, json, time, uuid, requests
KEY = "aid_live_..." # panelden
BASE = "https://www.aidiance.com/api/v1"
def call(method, resource, query=None, json_body=None):
ts = str(int(time.time()))
nonce = uuid.uuid4().hex
body = b""
if json_body is not None:
body = json.dumps(json_body, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
q_items = []
if query:
for k in sorted(query):
if k == "resource":
continue
q_items.append("%s=%s" % (requests.utils.quote(str(k), safe=""), requests.utils.quote(str(query[k]), safe="")))
canon_q = "&".join(q_items)
payload = "\n".join([ts, nonce, method.upper(), resource.lower(), canon_q, hashlib.sha256(body).hexdigest()])
sig = hmac.new(KEY.encode("utf-8"), payload.encode("utf-8"), hashlib.sha256).hexdigest()
headers = {
"Authorization": "Bearer " + KEY,
"X-Aidiance-Timestamp": ts,
"X-Aidiance-Nonce": nonce,
"X-Aidiance-Signature": sig,
"Content-Type": "application/json",
}
url = BASE + "/" + resource
if query:
url += "?" + "&".join("%s=%s" % (k, requests.utils.quote(str(query[k]), safe="")) for k in query)
if method == "GET":
return requests.get(url, headers=headers, timeout=20)
headers["X-Aidiance-Idempotency-Key"] = uuid.uuid4().hex
return requests.post(url, data=body, headers=headers, timeout=20)
print(call("GET", "conversations", {"channel": "whatsapp", "limit": "20"}).json())
print(call("POST", "messages", json_body={
"conversation_id": "wa:TOKEN:905551112233",
"text": "Merhaba"
}).json())
print(call("GET", "templates", {"assistant_token": "TOKEN"}).json())
print(call("POST", "messages", json_body={
"channel": "whatsapp",
"assistant_token": "TOKEN",
"to": "905551112233",
"template": {"name": "karsilama", "language": "tr", "body_variables": ["Ayşe"]}
}).json())
PHP örneği (imza)
function aidiance_sign($key, $ts, $nonce, $method, $resource, $canonQuery, $body) {
$bodyHash = hash('sha256', $body === null ? '' : $body);
$payload = $ts."\n".$nonce."\n".strtoupper($method)."\n".strtolower($resource)."\n".$canonQuery."\n".$bodyHash;
return hash_hmac('sha256', $payload, $key);
}
GET konuşma listesi için canonicalQuery örneği: channel=whatsapp&limit=20 (alfabetik).
Güvenlik kuralları
- Anahtarı git’e, frontend’e veya log’a yazmayın. Sızıntıda panelden hemen iptal edin.
- Mümkünse IP allowlist kullanın (sunucu çıkış IP’niz).
- Gönderim yetkisini yalnızca ihtiyaç varsa verin; salt okuma anahtarı ayrı üretin.
- Nonce’u her istekte yenileyin; aynı imzayı tekrar kullanmayın.
- Webhook gizli anahtarını (
whsec_…) yalnızca sunucuda saklayın; sızdığını düşünüyorsanız panelden yenileyin. - Bu API mobil uygulama oturum API’sinden (
/app_api/) ayrıdır.