Kampanyalar API
Sunucu anahtarı. Mutasyonlar için campaigns:write, istatistik için campaigns:read.
POST /v1/campaigns — taslak oluştur
Idempotency-Key kabul eder.
{
"name": "Hafta sonu indirimi",
"content": { "tr": { "title": "…", "body": "…" }, "en": { "title": "…", "body": "…" }, "_default": "tr" },
"segment": { "field": "tags.marketingOptIn", "op": "eq", "value": true },
"schedule": { "type": "at", "at": "2026-10-03T07:00:00Z" },
"data": { "screen": "sale" },
"ttl": 259200, "collapseId": "weekend-sale", "priority": "high",
"presentation": { "sound": "default", "threadId": "promotions" },
"bypass": { "frequencyCap": false },
"experiment": {
"sampleRate": 0.5,
"variants": [
{ "id": "a", "name": "Kontrol", "weight": 1, "content": { "tr": { "title": "…", "body": "…" }, "_default": "tr" } },
{ "id": "b", "name": "Emoji", "weight": 1, "content": { "tr": { "title": "… ⚡", "body": "…" }, "_default": "tr" } }
]
}
}
| Alan | Notlar |
|---|---|
name | 1–200 karakter, içsel |
content | templateId ya da silent: true verilmediyse zorunlu; deneyde yedek |
templateId | bir şablondan başla; istek alanları şablonunkileri ezer |
segment | herkes için atlayın |
segmentId | bir kayıtlı segment; segment ile birlikte değil. Gönderim anında kopyalanır. |
schedule | {type:"now"} (varsayılan) · {type:"at", at} · {type:"user_timezone", localTime:"HH:MM"} · {type:"recurring", every:"day"|"week", daysOfWeek?, localTime, timezone, until?} |
silent | arka plan push'u, içerik gerekmez; web atlanır. Bkz. Sessiz push |
experiment | 2–4 varyant; bkz. A/B testi. silent ile değil. |
| gerisi | Bildirimler'deki gibi |
201 { "id": "66f3…", "status": "draft" }. Henüz hiçbir şey gönderilmedi.
POST /v1/campaigns/:id/send
Gövde yok. draft ya da scheduled'dan:
- zamanlama
now→202 { "status": "sending" }, fan-out kuyrukta; at/user_timezone→202 { "status": "scheduled" }, gecikmeli iş olarak tutulur;recurring→202 { "status": "active" }, bir job scheduler kurulur ve her tetiklenme bir gönderim (recurringOftaşıyan alt kampanya) üretir. Bkz. Zamanlama.
Kampanyanın segmentId'si varsa kayıtlı segmentin tanımı şimdi kopyalanır (segment silindiyse 404).
Kampanya başka durumdaysa ya da içeriği yoksa (metni bitmemiş panel taslağı) 409 invalid_state.
POST /v1/campaigns/:id/cancel
draft, scheduled ya da active'den → 200 { "status": "cancelled" }; gecikmeli iş ya da tekrarlayan scheduler kaldırılır. Fan-out başladıysa 409 invalid_state. Tekrarlayan kampanyanın önceden ürettiği gönderimler ayrı kampanyalardır, etkilenmez.
POST /v1/campaigns/:id/experiment/winner
{ "variant": "b" }
202 { "id": "<takip kampanyası>", "status": "sending" }. Kazanan içeriği tutulan kalana, remainderOf ile geri bağlı yeni bir kampanya olarak gönderir. Hatalar: 409 (deney değil / kalan yok / zaten gönderildi / hâlâ gönderiliyor), 422 (bilinmeyen varyant). Bkz. A/B testi.
GET /v1/campaigns/:id/stats
{
"id": "66f3…",
"status": "sent",
"stats": {
"queued": 1650, "sent": 1534, "failed": 49, "skipped": 67,
"delivered": 1396, "opened": 433, "clicked": 173,
"variants": {
"a": { "sent": 770, "failed": 24, "skipped": 30, "delivered": 700, "opened": 180, "clicked": 70 },
"b": { "sent": 764, "failed": 25, "skipped": 37, "delivered": 696, "opened": 253, "clicked": 103 }
}
},
"rates": { "delivery": 0.91, "open": 0.3102, "click": 0.1239 }
}
rates.open ve rates.click ulaşana göredir; payda 0 ise null. variants yalnızca deneylerde bulunur. Cihazlar açılma bildirdikçe sayaçlar status sent olduktan sonra da hareket eder.
Yaşam döngüsü
Public API'de GET /v1/campaigns listesi ya da DELETE yoktur; panel ikisine de admin yüzeyinden sahiptir. Oluşturduğunuz id'lerin kaydını kendiniz tutun.