Node.js SDK
@pushizo/node — Node.js ≥ 20, ESM, OpenAPI'den türetilmiş tipler; bildirim, kullanıcı, olay, webhook imza doğrulama, journey ve tüm public API.
@pushizo/node yalnızca sunucuda kullanılır (API anahtarı istemciye gömülmez). Yerleşik fetch, üstel geri çekilmeli yeniden deneme, otomatik idempotency anahtarı ve @pushizo/api-client tipleri.
Kurulum ve başlatma
npm install @pushizo/nodeimport { Pushizo } from '@pushizo/node';
const hs = new Pushizo({
apiKey: process.env.HS_API_KEY!, // hs_live_… (Organizasyon → API anahtarları)
appId: process.env.HS_APP_ID, // çağrılarda appId verilmezse kullanılır
baseUrl: 'https://api.example.com', // yerel: http://localhost:4000
maxRetries: 3, // 429/5xx için üstel geri çekilme
timeoutMs: 30_000,
autoIdempotencyKey: true, // notifications.create için otomatik UUID
});Bildirim gönderme
const result = await hs.notifications.create({
idempotency_key: `order-${order.id}`,
target: { include_aliases: { external_id: [userId] } },
headings: { tr: 'Siparişiniz yola çıktı', en: 'Your order has shipped' },
contents: { tr: '…', en: '…' },
url: `https://example.com/orders/${order.id}`,
data: { order_id: order.id },
channels: ['ios_push', 'android_push', 'web_push'],
send_after: new Date(Date.now() + 60_000).toISOString(),
});
// result.id (msg_…), result.status, result.recipients_estimate, result.external_id_missing
await hs.notifications.get(result.id);
await hs.notifications.list({ limit: 50, status: 'completed' });
await hs.notifications.cancel(result.id);
await hs.notifications.deliveries(result.id, { limit: 100 });
await hs.notifications.estimate({ target: { included_segments: ['seg_…'] } });Aynı idempotency_key + aynı gövde aynı yanıtı döndürür; farklı gövde 409. Hedef boşsa 422 HS_NO_RECIPIENTS.
E-posta, SMS ve bildirim kutusu
await hs.notifications.create({
idempotency_key: `shipped-${order.id}`,
target: { include_aliases: { external_id: [userId] }, channels: ['email', 'sms'] },
contents: { tr: 'Siparişin kargoda', en: 'Your order shipped' }, // SMS gövdesi
email_subject: 'Siparişin yolda',
email_mjml: mjmlSource, // ya da email_body (hazır HTML)
email_preheader: 'Kargo takip numaran içeride',
email_from_name: 'Mağaza', email_from_address: 'no-reply@example.com', email_reply_to_address: 'destek@example.com',
sms_from: 'MAGAZA',
add_to_inbox: true, inbox_ttl: 7 * 86_400,
});Alanların anlamı: Mesajlaşma. Tipler CreateNotificationInput ile OpenAPI'den gelir.
Kullanıcılar, abonelikler, olaylar, kanallar
await hs.users.upsert({ external_id: 'user_42', tags: { plan: 'pro' }, language: 'tr' });
await hs.users.getByExternalId('user_42');
await hs.users.update('external_id', 'user_42', { tags: { plan: 'free' } });
await hs.users.addAliases('external_id', 'user_42', { crm_id: 'C-1' });
await hs.users.addSubscription('external_id', 'user_42', { channel: 'email', token: 'a@b.c' });
await hs.users.delete('external_id', 'user_42');
await hs.users.list({ q: 'user_', limit: 20 });
await hs.users.search({ definition: { all: [{ field: 'tags.plan', op: 'eq', value: 'pro' }] }, limit: 50 });
await hs.subscriptions.get('sub_…'); await hs.subscriptions.update('sub_…', { opted_in: false });
await hs.subscriptions.setOwner('sub_…', 'user_42'); await hs.subscriptions.delete('sub_…');
await hs.events.send([{ external_id: 'user_42', name: 'purchase', properties: { sku: 'A1' }, value: 49.9, occurred_at: new Date().toISOString() }]);
await hs.channels.list(); await hs.channels.validate('android_push');
await hs.apps.list(); await hs.organization.get(); await hs.organization.usage({ days: 30 });Suppression list
const page = await hs.suppressions.list({ channel: 'email', reason: 'bounce', limit: 50 });
// page.data[i] → { id, channel, value_masked: 'a***e@example.com', reason, source, expires_at }; page.next_cursor, page.has_more
const s = await hs.suppressions.create({ channel: 'sms', value: '+905321234567', reason: 'manual', note: 'müşteri talebi' });
await hs.suppressions.remove(s.id);Identity verification
const hash = Pushizo.identityHash(process.env.HS_SDK_SECRET!, externalId); // HMAC-SHA256
res.json({ external_id: externalId, identity_hash: hash }); // istemci SDK login(externalId, hash)Webhook'lar
Endpoint yönetimi: hs.webhooks.list / create / get / update / delete / rotateSecret / test / deliveries / replay (admin). Alıcı tarafında imzayı ham gövdeyle doğrulayın:
import express from 'express';
import { constructWebhookEvents, WebhookSignatureError } from '@pushizo/node';
app.post('/hooks/pushizo', express.raw({ type: 'application/json' }), (req, res) => {
try {
const events = constructWebhookEvents({ payload: req.body, header: req.headers['pushizo-signature'], secret: process.env.HS_WEBHOOK_SECRET! });
for (const event of events) enqueue(event); // event.id (Pushizo-Event-Id) ile tekrarları ayıklayın
res.sendStatus(204);
} catch (err) {
if (err instanceof WebhookSignatureError) return res.status(400).send(err.reason);
throw err;
}
});Ayrıntılar: Webhook'lar.
Journey'ler
const journey = await hs.journeys.create({ name: 'Sipariş sonrası' });
await hs.journeys.saveDraft(journey.id, { graph: { nodes, edges }, settings: { re_entry: { mode: 'never' } } });
const { version, issues } = await hs.journeys.publish(journey.id);
const { entered, run } = await hs.journeys.triggerRun(journey.id, { external_id: 'u-1', context: { order_id: 'o-42' } });
await hs.journeys.stats(journey.id, { version });
await hs.journeys.listForUser('external_id', 'u-1');Yaşam döngüsü: pause, resume, archive, duplicate; updateNode, versions, exitRun. Graf biçimi: Journey'ler.
Tüm kaynaklar
SDK api/openapi.yaml'daki public işlemlerin tamamını kapsar (kapsam testi her işlemi bir metoda eşler): organization, apps, notifications (history, exportEvents, estimate dahil), users (getIdentity, export, search), subscriptions (getUserIdentity, updateByToken), events (tanımlar dahil), channels, suppressions, webhooks, segments, templates (copyToApp), campaigns (variantStats, selectWinner), journeys, inAppMessages, inbox, preferences, analytics (format: 'csv'), exports, imports (multipart), apiKeys (rotate). Sayfalı uçlar için hs.paginate(...) async iterator.
Hatalar
import { PushizoError } from '@pushizo/node';
try { … } catch (e) {
if (e instanceof PushizoError) { e.status; e.code; e.requestId; e.details; e.retryable; }
}Kodlar: hata kataloğu.
Yeniden deneme politikası
Yeniden denemeler üstel geri çekilmeyle (0,3 / 1 / 3 sn; Retry-After başlığı varsa ona uyulur) en fazla maxRetries kez yapılır. Sunucuda tekrarlanması güvenli olmayan isteklerin çift işlenmemesi için kural HTTP metoduna göre değişir:
| Durum | GET, HEAD, OPTIONS, PUT, DELETE | POST, PATCH |
|---|---|---|
429 | Yeniden denenir | Yeniden denenir (istek işlenmeden reddedilmiştir) |
5xx, zaman aşımı, gönderim sonrası bağlantı kopması | Yeniden denenir | Yalnızca Idempotency-Key varsa |
İstek hiç gönderilemedi (ECONNREFUSED, ENOTFOUND/EAI_AGAIN DNS hatası, ENETUNREACH/EHOSTUNREACH, bağlantı zaman aşımı) | Yeniden denenir | Yeniden denenir |
Diğer 4xx | Denenmez | Denenmez |
5xx ya da gönderim sonrası ağ hatasında sunucu isteği işlemiş olabilir; anahtarsız bir POST/PATCH tekrarı çift bildirim veya kayıt üretebilir. notifications.create ve users.upsert anahtar verilmezse otomatik UUID üretir (otomatik anahtar kapatılmadıysa), bu yüzden bu iki çağrı güvenle yeniden denenir. notifications.create anahtarı gövdedeki idempotency_key alanında taşır; bu da sayılır. Başka bir POST/PATCH çağrısının da yeniden denenmesini istiyorsanız anahtarı kendiniz verin: hs.users.upsert(body, appId, { idempotencyKey: 'crm-42' }) ya da notifications.create({ idempotencyKey, … }). Yeniden denemelerde aynı anahtar gönderilir; API aynı anahtarla 24 saat içinde gelen tekrarı ilk yanıtla karşılar.
Unity SDK
com.pushizo.unity — Android ve iOS yerel SDK'larını saran UPM paketi (Unity 2021.3+); push, in-app, bildirim kutusu, tercihler, otomatik iOS/Android derleme ayarları.
PHP SDK
pushizo/pushizo-php — PHP ≥ 8.1, yalnızca ext-curl ve ext-json; bildirim, kullanıcı, olay, webhook imza doğrulama, journey ve tüm public API. Laravel örneği.