Gönderim
Push çıkarmanın iki yolu var. İçeriği, teslimat seçeneklerini, worker'ı ve raporu paylaşırlar; kime ve ne zaman konusunda ayrılırlar.
| Transactional | Kampanya | |
|---|---|---|
| Uç | POST /v1/notifications | Sihirbaz ya da POST /v1/campaigns sonra POST /v1/campaigns/:id/send |
| Adresleme | belirli kullanıcılar / cihazlar, segment ya da herkes | segment ya da herkes |
| Zaman | hemen | şimdi, belirli saat, kullanıcının yerel saati ya da tekrarlayan |
| Durum | kampanya kimliğiyle 202, transactional: true | draft → scheduled → sending → sent |
| A/B | hayır | evet (sessiz gönderimde değil) |
| Tipik kullanım | sipariş kargoda, yeni mesaj, şifre sıfırlama | promosyon, duyuru, yeniden etkileşim |
İkisi de bir kampanya satırı yazar: her push'taki izleme kimliği bir campaignId gömer; transactional gönderimin delivered/opened sayaçlarının düşeceği bir yer olmalı. Panel listesinde görünür ve tam raporu vardır.
Transactional — POST /v1/notifications
curl -X POST https://push.example.com/v1/notifications \
-H "Authorization: Bearer sk_live_…" \
-H "content-type: application/json" \
-H "Idempotency-Key: order-48213-shipped" \
-d '{
"target": { "externalIds": ["user_123"] },
"content": {
"en": { "title": "Your order is on its way", "body": "Order #48213 ships today.", "url": "acme://orders/48213" },
"tr": { "title": "Siparişin yola çıktı", "body": "#48213 bugün kargoda.", "url": "acme://orders/48213" },
"_default": "en"
},
"data": { "screen": "order", "id": "48213" },
"collapseId": "order-48213",
"ttl": 86400,
"bypass": { "quietHours": true }
}'
202 { "id": "…", "status": "sending" }. API doğrular, kampanyayı yazar, fan-out işini kuyruğa atar ve döner — teslimat worker'da olur.
Hedefler — tam olarak biri
| Seçici | Ulaşır | Sınır |
|---|---|---|
externalIds: ["user_123", …] | o kullanıcıların bildirime açık her cihazı | 1 000 id |
userIds: ["<ObjectId>", …] | aynısı, bizim id'lerle | 1 000 |
subscriptionIds: ["<ObjectId>", …] | tam o cihazlar | 1 000 |
segment: { … } | segment DSL'e uyan cihazlar | — |
segmentId: "<ObjectId>" | bir kayıtlı segment; tanımı gönderim anında kopyalanır | — |
all: true | bildirime açık her cihaz | — |
Bilinmeyen external id'ler sessizce atlanır (gönderecek şey yoktur). Yanıt her zaman 202dir — gerçekte ne olduğu için /v1/campaigns/:id/stats'a bakın.
Teslimat alanları (iki tür)
| Alan | Varsayılan | Anlamı |
|---|---|---|
content | content / templateId / silent'ten biri | Dil başına metin. Bkz. İçerik. |
templateId | — | Metni ve teslimat varsayılanlarını bir şablondan al. İstekte verilen alanlar şablonunkileri ezer. |
silent | false | Arka plan push'u: hiçbir şey gösterilmez, uygulama data ile uyandırılır. content gerekmez. Bkz. Sessiz push. |
data | — | Push ile giden düz string → string haritası. |
ttl | 259200 (3 gün) | Cihaz çevrimdışıyken push servisinin deneyeceği saniye. En çok 4 hafta. |
collapseId | — | Aynı kimlikli yeni push teslim edilmemiş eskisini değiştirir. |
priority | "high" | high → APNs 10, FCM high. normal → 5 / normal. Yalnızca teslimat aciliyeti; iOS'ta ne kadar gürültülü gösterileceği presentation.interruptionLevel'dadır. |
presentation | — | sound, badge, threadId, icon, interruptionLevel, relevanceScore, channelId. Bkz. İçerik. |
bypass | — | { frequencyCap?: true, quietHours?: true } — bir teslimat kuralını atla. |
Şablon kullanıldığında öncelik: istek alanı → şablon alanı → varsayılan.
Kampanyalar — API
# 1. oluştur (taslak)
curl -X POST https://push.example.com/v1/campaigns \
-H "Authorization: Bearer sk_live_…" -H "content-type: application/json" \
-d '{
"name": "Hafta sonu indirimi",
"content": { "tr": { "title": "Hafta sonu indirimi", "body": "Pazar'a kadar %30." }, "_default": "tr" },
"segment": { "and": [
{ "field": "tags.marketingOptIn", "op": "eq", "value": true },
{ "field": "lastActiveAt", "op": "gt", "value": "-30d" }
]},
"schedule": { "type": "user_timezone", "localTime": "19:30" }
}'
# 201 { "id": "66f1…", "status": "draft" }
# 2. gönder (ya da zamanla)
curl -X POST https://push.example.com/v1/campaigns/66f1…/send \
-H "Authorization: Bearer sk_live_…"
# 202 { "id": "66f1…", "status": "scheduled" }
# 3. hâlâ zamanlanmışken iptal et
curl -X POST https://push.example.com/v1/campaigns/66f1…/cancel -H "Authorization: Bearer sk_live_…"
# 4. istatistik
curl https://push.example.com/v1/campaigns/66f1…/stats -H "Authorization: Bearer sk_live_…"
schedule { "type": "now" } (varsayılan), { "type": "at", "at": "2026-10-01T09:00:00Z" }, { "type": "user_timezone", "localTime": "HH:MM" } ya da { "type": "recurring", … }. now kampanyasında send hemen kuyruğa atar; at ve user_timezone scheduled olur; recurring active olur ve her tetiklenmede bir gönderim üretir. Bkz. Zamanlama.
Segmenti olmayan kampanya herkese ulaşır. segmentId bir kayıtlı segmenti hedefler (segment ile birlikte değil); templateId bir şablondan başlar.
Kampanyalar — panel
Dört adımlı sihirbaz Panel › Kampanyalar'da belgelidir. API'nin ürettiği dokümanın tıpkısını üretir; 1. adımdaki Üretilen DSL paneli POST /v1/campaigns gövdesine koyacağınız segment JSON'unu gösterir.
202'den sonra ne olur
fan-out işi ──▶ kitleyi say ──▶ bildirime açık, geçersiz olmayan aboneliklerde cursor
──▶ her cihaz için: dil seç, A/B varyantı seç, notBefore hesapla (kullanıcı tz)
──▶ push-ios / push-android / push-web'e cihaz başına bir iş
worker ──▶ teslimat kuralları (sınır, sessiz saat) ──▶ kişiselleştir ──▶ transport
──▶ olay (sent | failed | skipped) + kampanya sayaçları + webhook
stats.queued fan-out bitince yazılır; diğer sayaçlar push'lar geçtikçe hareket eder. campaign.completed fan-out sonunda atılır — her push kuyruktadır, mutlaka gönderilmiş değil.
Rate limit
/v1/notifications API anahtarı başına sınırlıdır (SEND_RATE_LIMIT, varsayılan 100/dk). 1 000 kullanıcılı externalIds hedefli tek çağrı bir sayılır. Yüksek hacimli transactional trafik için id'leri çağrı başına toplayın ya da sınırı yükseltin.