Segmentler
Segment, abonelikleri seçen bir JSON ağacıdır. Panelin oluşturucusu üretir; POST /v1/campaigns, POST /v1/notifications (target.segment) ve POST /v1/segments/preview kabul eder; worker'ın fan-out'u MongoDB filtresine derler. Bir segment ad verilip kaydedilebilir ve yeniden kullanılabilir (aşağıda); her durumda kampanya tanımın kendi kopyasını taşır.
{
"and": [
{ "field": "tags.plan", "op": "in", "value": ["premium", "platinum"] },
{ "field": "lastActiveAt", "op": "gt", "value": "-7d" },
{ "not": { "field": "country", "op": "eq", "value": "CN" } },
{ "or": [
{ "field": "platform", "op": "eq", "value": "ios" },
{ "field": "tags.streak", "op": "gte", "value": 10 }
]}
]
}
Düğümler
| Düğüm | Anlamı |
|---|---|
{ "and": [ … ] } | tüm çocuklar eşleşir (1–50 çocuk) |
{ "or": [ … ] } | herhangi bir çocuk eşleşir (1–50) |
{ "not": … } | çocuk eşleşmez |
{ "field", "op", "value" } | abonelik alanı üzerinde bir koşul |
{ "event", "campaignId", "since"? } | davranışsal koşul — bkz. Davranışsal koşullar |
İç içelik derinliği sınırsızdır.
Alanlar
Abonelik dokümanında $ ile başlamayan herhangi bir noktalı yol. İşe yarayanlar:
| Alan | Tip | Örnek değerler |
|---|---|---|
platform | string | ios, android, web |
country | string | TR, DE |
language | string | tr, en-GB |
timezone | string | Europe/Istanbul |
tags.<key> | string / sayı / boolean | ne yazdıysanız |
externalId | string | |
lastActiveAt, lastNotifiedAt, createdAt | tarih | ISO tarih ya da göreli |
sessionCount | sayı | görülen oturum sayısı (30 dakika boşluk kuralı, sunucuda sayılır) |
lastSessionAt | tarih | son oturumun başlangıcı |
lastOpenedAt | tarih | bu cihazdan gelen son opened/clicked eventi |
appVersion, osVersion, deviceModel, browser | string | 3.4.1, 17.5, iPhone 15 Pro, chrome |
standalone | boolean | web: PWA olarak kurulu |
optedIn | boolean | genellikle temel filtreye bırakılır |
Tag'ler wildcard index'lidir (tags.$**); herhangi bir tag anahtarına filtre hızlıdır.
Operatörler
op | value | Derlenir |
|---|---|---|
eq / ne | string, sayı, boolean, null | field: v / { $ne: v } |
gt / gte / lt / lte | sayı ya da tarih string'i | { $gt: v } … |
in / nin | skaler dizisi (1–1000) | { $in: [...] } |
exists | boolean | { $exists: b } |
regex | string ≤ 256 | { $regex: v, $options: "i" } — büyük/küçük harf duyarsız |
Değerler yalnızca skalerdir. Nesne değer doğrulamada reddedilir — API üzerinden $where ya da $ne operatörü kaçırmayı engelleyen budur.
Göreli tarihler
Karşılaştırma operatörleri için ^-(\d+)([smhd])$ ile eşleşen string derleme anında Date'e çevrilir:
| Kısaltma | Anlamı |
|---|---|
-30s | 30 saniye önce |
-15m | 15 dakika önce |
-12h | 12 saat önce |
-7d | 7 gün önce |
{ "field": "lastActiveAt", "op": "gt", "value": "-7d" } = son bir haftada etkin; "op": "lt" = bir haftadır etkin değil. Mutlak ISO string'ler (2026-08-01) de çalışır.
Davranışsal koşullar
"Cuma indirimini açtı", "hiçbir promosyona tıklamadı": bir cihazın önceki bir kampanyayla ne yaptığına dair koşul.
{ "and": [
{ "field": "country", "op": "eq", "value": "TR" },
{ "not": { "event": "opened", "campaignId": "64b7f3a1c2d4e5f601234568", "since": "-30d" } }
]}
| Alan | Değerler |
|---|---|
event | sent, delivered, opened, clicked |
campaignId | eventleri sayılacak kampanya (gönderilmiş biri; anlık gönderimlerin de kimliği vardır) |
since | isteğe bağlı; yalnızca bu andan sonraki eventler — göreli (-30d) ya da ISO |
"Yapmadı" için not içine alın. Eventler ayrı koleksiyonda durduğu için API ve worker her koşulu önce bir abonelik kimliği kümesine çözer (koşul başına bir distinct), ağacı ondan sonra derler; sihirbazdaki Etkileşim düğmesi bunları kurar. Küme, önceki kampanyanın kitlesi büyüklüğündedir — birkaç yüz bin cihaza kadar sorunsuzdur.
"Son zamanlarda hiçbir şey açmadı" için lastOpenedAt alanını kullanın; arama gerektirmez.
Kayıtlı segmentler
Kayıtlı segment adlandırılmış bir tanımdır (segments koleksiyonu): panelde Segmentler sayfasından, sihirbazda Segment olarak kaydet ile ya da POST /v1/segments ile oluşturulur. Son bilinen boyutunu gösterir ve yeniden sayılabilir.
Kampanyalar ona segmentId (API) ile ya da sihirbazda seçerek başvurur. Tanım gönderim anında kampanyaya kopyalanır: kayıtlı segmenti sonradan düzenlemek gelecek kampanyaları değiştirir, zamanlanmış ya da aktif olanı asla. Sihirbazda seçili bir segmenti düzenlemek bağı koparır — kampanya kendi kopyasını tutar, kayıtlı olan dokunulmaz kalır.
Temel filtre
Ne yazarsanız yazın kiracı filtresiyle and'lenir — appId, optedIn: true, invalidatedAt: null. Başka uygulamanın satırlarına ulaşamazsınız; segmentte optedIn: false yazsanız bile çıkmış ya da ölü cihazları hedefleyemezsiniz.
Önizleme
curl -X POST https://push.example.com/v1/segments/preview \
-H "Authorization: Bearer sk_live_…" -H "content-type: application/json" \
-d '{ "segment": { "field": "tags.plan", "op": "eq", "value": "premium" } }'
# { "count": 512, "byPlatform": { "ios": 260, "android": 200, "web": 52 } }
Sihirbazın Eşleşen abone paneli siz düzenledikçe aynı ucu çağırır. Geçersiz segment, bozuk düğümün yoluyla 422 invalid_segment döner.
Tarifler
| Hedef | Segment |
|---|---|
| Herkes | segment'i atlayın |
| Yalnızca iOS | { "field": "platform", "op": "eq", "value": "ios" } |
| Uzaklaşmış kullanıcılar | { "field": "lastActiveAt", "op": "lt", "value": "-14d" } |
| Hiç bildirim almamış | { "field": "lastNotifiedAt", "op": "eq", "value": null } |
| Türkiye'de premium, web hariç | { "and": [ {"field":"tags.plan","op":"eq","value":"premium"}, {"field":"country","op":"eq","value":"TR"}, {"not": {"field":"platform","op":"eq","value":"web"}} ] } |
| Tag'i olan | { "field": "tags.firstName", "op": "exists", "value": true } |
| 3.4'ten eski uygulama sürümü | { "field": "appVersion", "op": "regex", "value": "^3\\.[0-3]\\." } (sürümler string'dir; lt sözlük sırasına göre karşılaştırır) |
| iOS Safari'de kurulu PWA'lar | { "and": [ {"field":"platform","op":"eq","value":"web"}, {"field":"browser","op":"eq","value":"safari"}, {"field":"standalone","op":"eq","value":true} ] } |