İçeriğe geç

Ingest API

Markdown

Sipariş, teslimat ve e-posta olaylarını Sayproof'a gönderen sunucu endpoint'lerinin özeti.

Bu endpoint’lere istek sunucudan sunucuya gönderilir. Ayrıntılı açıklama ve dil bazında örnek kodlar için: Sipariş ve teslimat aktarımı, E-posta teslim bildirimleri.

Endpoint Yöntem
/v1/ingest/orders, /v1/ingest/deliveries Authorization: Bearer <sunucu-anahtarı>; anahtarın sipariş gönderme (orders) izni olmalıdır. İsteğe bağlı olarak imzalı gönderim şifresiyle imza da kullanılabilir.
/v1/mail-events/generic E-posta teslim bildirimi şifresiyle imza

İstekte Authorization: Bearer header’ı varsa sunucu anahtarı denetlenir; yoksa aşağıdaki imza header’ları aranır.

Header Değer
X-Sayproof-Secret Şifre kimliği (panelde şifre tablosunun Şifre kimliği sütunu; şifrenin adı değil)
X-Sayproof-Timestamp Saat dilimini içeren ISO 8601 zaman değeri; Sayproof’un saatinden en fazla ±5 dakika farklı olabilir
X-Sayproof-Signature hex(HMAC-SHA256(şifre, zaman + "." + body))

İmza, gönderilen byte’ların kendisi üzerinden hesaplanır.

Endpoint Body Yanıt
POST /v1/ingest/orders Tek bir sipariş ya da {"channel", "orders": […]} (en fazla 100 sipariş) {"accepted", "orders": [{"external_id", "id"}]}
POST /v1/ingest/deliveries Tek bir teslimat ya da {"deliveries": […]} (en fazla 100 kayıt) {"accepted", "unknown": [{"external_id", "line"}]}
POST /v1/mail-events/generic Tek bir olay ya da {"events": […]} (en fazla 500 olay) {"accepted", "matched", "duplicates", "ignored", "opted_out"}

E-posta hizmetlerine özel endpoint’lerde (/v1/mail-events/ses, sendgrid, postmark, mailgun) imza yerine adreste markaya özel bir erişim kodu bulunur; bu adresler panelde gösterilir.

  • Sipariş listesi bütün olarak işlenir. Siparişlerden biri reddedilirse aynı istekteki diğer siparişler de kaydedilmez.
  • channel body’nin en üstünde, her siparişte ya da ikisinde birden verilebilir; ikisi birden verilmişse siparişteki değer geçerlidir. Siparişin pazarı kanalın pazarıyla aynı olmalıdır; değilse istek 400 invalid / market_channel_mismatch: <pazar> yanıtı alır.
  • external_id, line_reference, variant_key, group_key, catalog_id ve customer_key en fazla 128 karakter olabilir.
  • Aynı sipariş yeniden gönderildiğinde güncellenir, kopyası oluşturulmaz. Sonraki gönderimde yer almayan sipariş satırları silinmez. Müşteri bilgileri takma değere çevrilmiş bir sipariş yeniden gönderilirse customer_email, customer_phone ve customer_key geri yazılmaz.
  • Teslimat listesinde tanınmayan satırlar isteğin başarısız olmasına neden olmaz; yanıttaki unknown listesinde döner. Tanınmayan bir durum değeri ise isteğin tamamının geri alınmasına neden olur.
  • Aynı teslimat bilgisi (aynı satır, durum, kaynak ve zaman) ikinci kez kaydedilmez.
  • Tahmine dayalı bir delivered bilgisi satırın durumunu belirlemez ve doğrulanmış teslimat bilgisini gizlemez.
  • İade ya da iptal edilmiş bir satır sipariş verisinde delivered_at olmadan yeniden delivered olarak gelirse bu durum yok sayılır.
  • Ödeme refunded ya da voided durumuna geçtiğinde ya da satır returned olarak bildirildiğinde, daha önce yazılmış ürün yorumlarının kanıtına “Yorumdan sonra iade edildi” işareti düşer ve otomatik kontroller yeniden çalışır; süreç deneyimi yorumları bu işareti almaz.
  • Aynı e-posta olayı (aynı event_id) ikinci kez işlenmez.
Alan Değerler
payment_state pending, paid, partially_refunded, refunded, voided
fulfilment_state, state placed, preparing, shipped, in_transit, delivered, cancelled, returned
source platform, carrier, manual, estimated
confidence verified, estimated
E-posta olayı type delivered, deferred, bounced, complained, opened, unsubscribed

Hata kodları için: Hata kodları › Aktarım.

Sipariş ve teslimat endpoint’lerine istek sunucu anahtarıyla, e-posta olaylarına E-posta teslim bildirimi şifresiyle imzalanarak gönderilir. Aşağıdaki yardımcı fonksiyon ikisini de karşılar: sunucu anahtarı verilirse Authorization header’ını, şifre verilirse imza header’larını ekler.

import { createHmac } from "node:crypto";
export async function sayproofPost(path, payload, auth) {
const body = JSON.stringify(payload);
const headers = { "Content-Type": "application/json" };
if (auth.serverKey) {
headers.Authorization = `Bearer ${auth.serverKey}`;
} else {
const timestamp = new Date().toISOString();
headers["X-Sayproof-Secret"] = auth.secretId;
headers["X-Sayproof-Timestamp"] = timestamp;
headers["X-Sayproof-Signature"] = createHmac("sha256", auth.secret).update(`${timestamp}.${body}`).digest("hex");
}
const answer = await fetch(`${process.env.SAYPROOF_BASE}${path}`, {
method: "POST",
headers,
body,
signal: AbortSignal.timeout(10000),
});
const result = await answer.json().catch(() => ({}));
if (!answer.ok) throw new Error(`${answer.status} ${result.error ?? ""} ${result.detail ?? ""}`.trim());
return result;
}
await sayproofPost(
"/v1/ingest/deliveries",
{
deliveries: [
{ external_id: "ORD-1001", line_reference: "1", state: "delivered", observed_at: "2026-09-27T09:00:00+03:00", source: "carrier" },
],
},
{ serverKey: process.env.SAYPROOF_SERVER_KEY }
);