Postlip Metrics Tracking API — v1
Ürünlerin Postlip Metrics'e olay göndermesi için sözleşme. Segment Tracking API Spec ile uyumludur: aynı uçlar, aynı mesaj alanları, aynı kimlik doğrulama. Segment ya da RudderStack istemci kütüphaneleri host/apiHost ayarı Postlip Metrics'e çevrilerek kullanılabilir; Postlip Metrics'in kendi SDK'ları (@metrics/web, @metrics/node) ek olarak imza, ret sebebi loglama ve şemadan tip üretimi sunar.
Bu sayfa derleme sırasında depodaki docs/api/tracking-api.md dosyasından üretilir.
- Taban adres:
https://collect.<alan>/v1(geliştirme:http://localhost:7110/v1) - Makine tarafından okunur belge:
openapi/tracking.json(koddan üretilir)
1. Kavramlar
2. Kimlik doğrulama
Üç yoldan biri (öncelik sırasıyla):
Authorization: Basic base64("<writeKey>:") # Segment uyumlu
Authorization: Bearer <writeKey>
{ "writeKey": "<writeKey>", ... } # yalnız tarayıcı beacon'ı (text/plain gövde)İmza (sunucu kaynakları)
Kaynak ayarında "İmza zorunlu" açıksa imzasız istek 401 signature_required alır.
Metrics-Signature: t=1793892559,v1=5f0c…e1a2v1 = hex(HMAC-SHA256(signingSecret, t + "." + hamGövde)). t Unix saniyedir; sunucu saatinden ±300 sn dışındaysa 401 signature_expired. Birden çok v1= değeri (anahtar yenileme dönemi) kabul edilir.
3. Uçlar
POST /v1/ping gövdesi {} (imzalanır), yanıtı {"success": true, "sourceId", "appId", "environment", "test", "signature": "valid" | "absent"}; anahtar ya da imza hatasında §6'daki 401/403.
Gövde application/json; tarayıcıdan text/plain;charset=UTF-8 da kabul edilir (CORS ön isteği olmasın diye).
GET /v1/config/{writeKey}?schemaHints=1 (2026-11-08'de eklendi; geriye uyumlu — parametresiz yanıt değişmedi) yanıta schemaHints ekler: { "mode": "strict" | "lenient" | "discover", "events": [{ "name", "required": [özellik anahtarları] }], "blocked": [olay adları], "truncated": bool } — engellenmemiş tanımlar ve zorunlu özellikleri, engellenen olaylar (en çok 300'er), yalnız adlar (tip, açıklama, kişisel veri sınıfı yok). Web SDK'nın npm paketi debug kipinde ister ve tanımsız, engellenen olay ya da eksik zorunlu özellik için konsola uyarı yazar; gönderim bundan etkilenmez.
4. Mesaj alanları
Ortak alanlar (Segment Spec):
Tipe özel alanlar:
Standart properties (bütün olaylarda anlamlı): revenue, value, currency (ISO 4217; listede olmayan kod currency_unknown uyarısı alır), tax, net_revenue, order_id / transaction_id, plan_id, test (boolean — anahtar canlı olsa da test işaretler). Bunlar olay kataloğunda tanımlanmasa da her doğrulama kipinde (strict dahil) kabul edilir, tipleri her zaman denetlenir; olayda aynı anahtarla tanım varsa tanım geçerlidir. Liste: @metrics/contracts → STANDARD_PROPERTIES.
5. context
Segment Spec'teki adlarla; Postlip Metrics'in kullandıkları:
Rızasız ziyaretçi (2026-11-08): kaynağın rıza kipi required iken analitik rızası olmayan tarayıcı mesajında (consent.analytics true değil; sunucu kaynakları hariç) sekmeye özgü anonymousId yerine günün ziyaretçi kimliği saklanır: ck_ + HMAC(günün tuzu, IP + tarayıcı + uygulama). Tuz her UTC günü rastgele üretilir ve gün bitince silinir — ertesi gün aynı tarayıcı başka ziyaretçidir, eski kimlik yeniden hesaplanamaz; IP yalnız girdidir, saklanmaz. userId gönderilmişse kişi yine onunla tanınır.
Tıklanan iletişim bağlantıları (2026-11-08): $click / $rageclick hedefi tel:, sms:, mailto: ya da WhatsApp (wa.me, api.whatsapp.com, web.whatsapp.com) bağlantısıysa saklanan hedefe tür eklenir (target.contact: phone, email, whatsapp) ve bağlantı şemasına ya da alan adına kısaltılır; $outbound WhatsApp adresi de yalnız alan adıyla saklanır. Numara ve adres hiç saklanmaz. Sistem olaylarına $pageleave.scroll_reversals (tamsayı, isteğe bağlı: yarım ekrandan büyük yön değişimi sayısı; aşırı kaydırma sinyali) eklendi; eski SDK'lar göndermez.
6. Yanıtlar
200
{
"success": true,
"accepted": 2,
"rejected": [
{
"index": 2,
"messageId": "purchase:9f2c",
"errors": [
{ "code": "property_required", "path": "properties.plan_id", "message": "plan_id zorunlu" }
]
}
],
"warnings": [
{ "index": 0, "code": "property_unplanned", "path": "properties.color" }
]
}Hız sınırı kaynak başınadır ve mesajları sayar (500 mesajlık parti 500 sayılır): sürekli dakikada 60.000, bir anda 10.000 mesaj (kurulumun ayarı). Aşan istek hiçbir şey saklamadan 429 alır; Retry-After beklenip aynı messageId'lerle tekrar gönderilir. OpenAPI belgesinde (tracking.json) 429 yanıtının gövdesi (Refusal) ve Retry-After başlığı tanımlı, varsayılan sınırlar x-limits'te rateLimitPerMinute ve rateLimitBurst (2026-11-08).
Uygulamanın trafik filtresi kuralları (panelde Ayarlar; ör. test kampanyası adları, ofis IP aralığı, QA kullanıcı kimliği, test hesabı groupId) eşleşen mesajı test, iç ya da bot trafiği işaretler; mesaj yine kabul edilir (200), ekranlar varsayılan olarak dışlar. Her uygulamaya hazır kurallar eklenir (reklam etiket test araçlarından gelen ziyaret, test / qa_ ile başlayan ya da _test ile biten kampanya adı → test; Postlip Metrics panelinden gelen ziyaret → iç), uygulama bunları düzenleyebilir ya da silebilir. Saklanan alanlara bakan kural (IP ve tarayıcı kimliği hariç) uygulamanın geçmiş trafiğini de arka planda yeniden işaretler; işaret yalnız eklenir (2026-11-08).
Hata kodları (errors[].code): invalid_message, event_name_missing, identity_missing, event_unplanned (strict), event_blocked, property_required, property_type, property_unplanned (strict), property_too_long, pii_detected, timestamp_out_of_range, message_too_large.
Uyarı kodları (warnings[].code; mesaj kabul edilmiştir): yukarıdaki kodların reddetmeyen kipteki karşılıkları (ör. property_unplanned, pii_detected) ve currency_unknown — properties.currency ISO 4217 listesinde değil; tutar saklanır ama kur bulunamadığı için uygulamanın para birimine çevrilmeyebilir (2026-11-08'de eklendi; geriye uyumlu) — ve property_out_of_range — sayı tanımın minimum / maximum aralığının dışında; değer saklanır (aykırı tutar işaretlenir, kaybolmaz). Bu sürümden önce aralık dışı sayı strict kipte reddediliyor, diğer kiplerde atılıyordu; artık her kipte uyarıyla kabul edilir (2026-11-08; daha geniş kabul, istemci değişikliği gerekmez). Kabul edilen mesajların uyarıları örneklenerek (istek başına en çok 20, kaynak ve dakika başına en çok 600) 7 gün saklanır: panelin canlı olay akışında mesajın yanında ve kaynak sağlığında (warningsLast24h) görünür.
7. Örnekler
7.1 Sunucudan kayıt olayı (imzalı)
BODY='{"userId":"usr_7c1e","event":"signup_completed","messageId":"signup:7c1e","timestamp":"2026-11-06T14:46:00+03:00","properties":{"signup_method":"email","plan_id":"pro"},"context":{"consent":{"analytics":true,"marketing":true},"attribution":{"first_touch":{"source":"google","medium":"cpc","campaign":"hp_search_brand","landing_path":"/","at":"2026-11-02T10:11:00Z"}},"clickIds":{"gclid":"Cj0KCQiA…"}}}'
T=$(date +%s)
SIG=$(printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "$SIGNING_SECRET" -hex | sed 's/^.* //')
curl -X POST https://collect.<alan>/v1/track \
-u "$WRITE_KEY:" -H "Content-Type: application/json" \
-H "Metrics-Signature: t=$T,v1=$SIG" -d "$BODY"7.2 Toplu gönderim
POST /v1/batch
{
"batch": [
{ "type": "identify", "userId": "usr_7c1e", "anonymousId": "a1b2c3", "traits": { "plan": "pro" } },
{ "type": "group", "userId": "usr_7c1e", "groupId": "acc_903427", "traits": { "team_size": "6-20" } },
{ "type": "track", "userId": "usr_7c1e", "event": "purchase_completed", "messageId": "purchase:HP9f2c",
"properties": { "transaction_id": "HP9f2c", "plan_id": "pro", "revenue": 5197.6, "net_revenue": 4331.33,
"tax": 866.27, "currency": "TRY", "billing_period": "yearly" } }
]
}7.3 Tarayıcı (script etiketi)
<script>
!function(){var m=window.metrics=window.metrics||[];if(m.load)return;m.q=[];["page","track","identify","group","alias","reset","consent","ready"].forEach(function(k){m[k]=function(){m.q.push([k].concat([].slice.call(arguments)))}});
var s=document.createElement("script");s.async=1;s.src="https://collect.<alan>/m.js";document.head.appendChild(s);
m.load=function(k,o){m.q.unshift(["load",k,o])};}();
metrics.load("pk_live_…", { consent: "required" });
metrics.page();
</script>7.4 Segment istemcisiyle
import { Analytics } from '@segment/analytics-node';
const analytics = new Analytics({ writeKey: 'pk_live_…', host: 'https://collect.<alan>', path: '/v1/batch' });
analytics.track({ userId: 'usr_7c1e', event: 'trial_started', properties: { plan_id: 'pro', trial_days: 14 } });(İmza zorunlu kaynaklarda Segment istemcisi imza atamaz; Postlip Metrics SDK'sını ya da imzasız sunucu kaynağı kullanın.)
8. Olay tasarımı önerileri
- Olay adı geçmiş zamanlı ve nesne + eylem:
signup_completed,trial_started,purchase_completed,demo_requested. Ad bir kez yayımlandıktan sonra değiştirilmez; yeniden adlandırma panelde takma adla yapılır. - Her iş olayını panelde bir iş rolüne bağlayın (
signup,purchase,lead…). Dashboard, huniler, reklam ROAS'ı ve dönüşüm geri gönderimi role bakar. - Para:
revenuevergi dahil brüt,net_revenuevergi hariç,taxvergi,currencyzorunlu. - Kişisel veri göndermeyin. Gerekirse (ör. Meta CAPI eşleşmesi) özelliği panelde
personal+hasholarak tanımlayın; Postlip Metrics özetler, ham değeri saklamaz. - Aynı gerçek olay için aynı
messageId'yi üretin (ödeme sağlayıcının geri çağrısı iki kez gelse de tek olay).