İçeriğe geç

Sipariş ve teslimat aktarımı

Markdown

Sipariş ve teslimat bilgisinin sunucu anahtarıyla Sayproof'a gönderilmesi.

Sayproof yorum yazma hakkını ve davetleri siparişlere dayanarak oluşturur. Bu nedenle mağaza sisteminizin siparişleri ve teslimatları Sayproof’a göndermesi gerekir. Aktarım sunucudan sunucuya yapılır ve her istek sunucu anahtarıyla gönderilir; böylece bilginin gerçekten sizden geldiği doğrulanır.

  • Sipariş oluşturulduğunda ve ödeme durumu değiştiğinde (ödendi, iade edildi, iptal edildi).
  • Bir sipariş satırı kargoya verildiğinde, teslim edildiğinde, iade ya da iptal edildiğinde.

Aynı siparişin yeniden gönderilmesi güvenlidir: sipariş güncellenir, kopyası oluşmaz. En basit yöntem, her değişiklikte siparişin tamamını yeniden göndermektir.

Davet gönderilebilmesi ve yorum yazılabilmesi için sipariş satırının teslim edilmiş, siparişin ödenmiş olması gerekir. Teslimattan sonra Sayproof, Davet gönderimi ekranındaki bekleme süresi (varsayılan 2 gün) dolduğunda daveti gönderir.

Endpoint İşlev
POST /v1/ingest/orders Siparişleri ve sipariş satırlarını kaydeder ya da günceller
POST /v1/ingest/deliveries Sipariş satırlarının teslimat durumlarını bildirir

Adresler panelde Entegrasyon › Sipariş aktarımı sekmesinin Mağazadan gönderim bölümündeki Siparişleri ve teslimatları gönderin kartında Kurulumda kullanılacak değerler listesinde Siparişler ve Teslimatlar satırlarında yer alır; aynı listede Kanal kodu da bulunur.

Her istek sunucu anahtarını Authorization header’ında taşır:

Header Değer
Authorization Bearer <sunucu-anahtarı>
Content-Type application/json

Kurallar:

  • Sunucu anahtarı Kanallar › Anahtarlar sekmesindeki Sunucu anahtarları kartında ya da kanal kurulum sihirbazının Anahtarlar adımında oluşturulur. SSR için kullandığınız anahtarla aynı anahtar olabilir.
  • Anahtarın sipariş gönderme (orders) izni olmalıdır. Panelden oluşturulan sunucu anahtarları bu izni kendiliğinden taşır.
  • Anahtar yalnızca sunucuda tutulur; tarayıcıya ya da sayfa koduna konmaz.
  • Siparişin kanalı body’deki channel alanından belirlenir.
export async function sendOrders(orders) {
const answer = await fetch(`${process.env.SAYPROOF_BASE}/v1/ingest/orders`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.SAYPROOF_SERVER_KEY}`,
},
body: JSON.stringify({ channel: "web", orders }),
});
if (!answer.ok) throw new Error(`sayproof_ingest_${answer.status}: ${await answer.text()}`);
return answer.json();
}
import json
import os
import requests
def send_orders(orders):
body = json.dumps({"channel": "web", "orders": orders}, ensure_ascii=False).encode("utf-8")
answer = requests.post(
f"{os.environ['SAYPROOF_BASE']}/v1/ingest/orders",
data=body,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {os.environ['SAYPROOF_SERVER_KEY']}",
},
timeout=10,
)
answer.raise_for_status()
return answer.json()
function sayproof_send_orders(array $orders): array
{
$body = json_encode(['channel' => 'web', 'orders' => $orders], JSON_UNESCAPED_UNICODE);
$curl = curl_init(getenv('SAYPROOF_BASE') . '/v1/ingest/orders');
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . getenv('SAYPROOF_SERVER_KEY'),
],
]);
$answer = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($answer === false || $status !== 200) {
throw new RuntimeException('sayproof_ingest_' . $status);
}
return json_decode($answer, true);
}
Terminal window
curl -X POST "$SAYPROOF_BASE/v1/ingest/orders" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAYPROOF_SERVER_KEY" \
--data '{"channel":"web","orders":[]}'

İmzalı gönderim isteğe bağlıdır. İsteklerini sunucu anahtarı yerine ortak bir şifreyle imzalamak isteyen ekipler için Kanallar › Anahtarlar sekmesinin altındaki Gelişmiş: imzalı gönderim şifreleri bölümünde İmzalı gönderim şifresi oluşturulur. İstekte Authorization: Bearer header’ı varsa Sayproof sunucu anahtarını, yoksa imzayı denetler. İmzalı her istek üç header taşır:

Header Değer
X-Sayproof-Secret İmzalı gönderim şifresinin kimliği: İmzalı gönderim şifreleri tablosunun Şifre kimliği sütunu. Şifrenin adı gönderilmez.
X-Sayproof-Timestamp İsteğin zamanı; saat dilimi içeren ISO 8601 biçiminde: 2026-09-28T07:30:00Z ya da 2026-09-28T10:30:00+03:00
X-Sayproof-Signature hex(HMAC-SHA256(şifre, zaman + "." + body))

Kurallar:

  • İmza, gönderilen byte’ların kendisi üzerinden hesaplanır. İmzaladıktan sonra JSON’u yeniden biçimlendirmeyin ve boşluk eklemeyin.
  • İstek zamanı Sayproof’un saatinden en fazla 5 dakika farklı olabilir; sunucunuzun saati senkronize olmalıdır.
  • Saat dilimi içermeyen zaman değerleri (2026-09-28T10:30:00) reddedilir.
  • Şifrenin kendisi hiçbir istekte gönderilmez; yalnızca imzayı hesaplamak için kullanılır.
import { createHmac } from "node:crypto";
export async function sendOrdersSigned(orders) {
const body = JSON.stringify({ channel: "web", orders });
const timestamp = new Date().toISOString();
const signature = createHmac("sha256", process.env.SAYPROOF_INGEST_SECRET)
.update(`${timestamp}.${body}`)
.digest("hex");
const answer = await fetch(`${process.env.SAYPROOF_BASE}/v1/ingest/orders`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Sayproof-Secret": process.env.SAYPROOF_INGEST_SECRET_ID,
"X-Sayproof-Timestamp": timestamp,
"X-Sayproof-Signature": signature,
},
body,
});
if (!answer.ok) throw new Error(`sayproof_ingest_${answer.status}: ${await answer.text()}`);
return answer.json();
}

Tek bir sipariş ya da en fazla 100 siparişten oluşan bir liste gönderilebilir:

{
"channel": "web",
"orders": [
{
"external_id": "ORD-1001",
"payment_state": "paid",
"market": "TR",
"language": "tr",
"placed_at": "2026-09-25T10:00:00+03:00",
"customer_email": "ayse@ornek.com",
"customer_key": "musteri-4821",
"items": [
{
"line_reference": "1",
"variant_key": "URUN-38",
"group_key": "URUN",
"title": "Koşu ayakkabısı",
"quantity": 1,
"fulfilment_state": "delivered",
"delivered_at": "2026-09-27T09:00:00+03:00"
}
]
}
]
}
Alan Zorunlu Açıklama
channel Hayır Kanal kodu (en fazla 32 karakter). Body’nin en üstünde verilirse istekteki tüm siparişlere, siparişin içinde verilirse yalnızca o siparişe uygulanır; ikisi birden verilmişse siparişteki değer geçerlidir. Hiçbiri verilmezse siparişin mevcut kanalı korunur.
external_id Evet Sipariş numarası (en fazla 128 karakter). Müşterinin sipariş doğrulamasında gireceği numaradır; büyük/küçük harfe duyarlıdır.
payment_state Evet pending, paid, partially_refunded, refunded, voided. Yorum ve davet için paid ya da partially_refunded gerekir.
market Hayır Pazar kodu; örneğin TR. Belirtilmezse kanalın pazarı kullanılır. Kanalın pazarından farklı bir pazar gönderilirse sipariş reddedilir (market_channel_mismatch: <pazar>).
language Hayır tr ya da en. Belirtilmezse kanalın dili kullanılır.
placed_at Evet Sipariş zamanı; saat dilimiyle birlikte.
customer_email Hayır Siparişteki e-posta adresi (en fazla 254 karakter). Davet bu adrese gönderilir; sipariş doğrulamasında ve oturum açmış müşteri sorgusunda bu adres kullanılır. Adres gönderilmezse davet gönderilmez.
customer_key Hayır Müşterinin sizin sisteminizdeki kimliği (en fazla 128 karakter). Günlük davet sınırı ve seri gönderim kontrolü bu kimliğe göre, kimlik yoksa e-posta adresine göre uygulanır.
customer_phone Hayır Siparişteki telefon numarası (en fazla 32 karakter); alan kabul edilir. Numara WhatsApp ile davet için kullanılacak. WhatsApp ile davet v2 sürümüyle gelene kadar telefon numarası saklanmaz. Sonra numara uluslararası biçimde saklanacak (+905321112233); ülke kodu olmayan numara kanalın pazarına göre tamamlanacak (Türkiye pazarında 0532 111 22 33 → +905321112233), tamamlanamayan numara saklanmayacak.
items[] Evet Sipariş satırları.

Siparişteki e-posta adresi, telefon ve müşteri numarası, yorum yazma süresi bitince ya da müşterinin KVKK silme talebiyle takma değere çevrilir; aynı sipariş sonradan yeniden gönderilse de bu alanlar geri yazılmaz, sipariş aynı kayda işlenir. Ayrıntılar için: Saklama süreleri.

Sipariş satırı alanları:

Alan Zorunlu Açıklama
line_reference Evet Satırın sipariş içindeki kimliği (en fazla 128 karakter). Her satır için bir yorum yazılabilir.
variant_key Evet Ürün kodu (en fazla 128 karakter). Sayfadaki container’ın data-review-product değeriyle aynı olmalıdır.
group_key Hayır Ürün grubu kodu (en fazla 128 karakter). Grup düzeyinde yorum gösterimi için gereklidir.
catalog_id Hayır Ürünün katalogdaki kimliği (en fazla 128 karakter).
title Hayır Ürün adı (en fazla 300 karakter). Yorum formunda gösterilir.
quantity Hayır Adet; varsayılan 1.
fulfilment_state Hayır placed (varsayılan), preparing, shipped, in_transit, delivered, cancelled, returned.
delivered_at Hayır Teslim zamanı. delivered durumundaki satırlarda gönderilmesi önerilir. Daha önce iade ya da iptal edilmiş bir satır delivered_at olmadan yeniden delivered durumuyla gelirse bu durum yok sayılır; satır gerçekten yeniden teslim edildiyse teslim zamanını gönderin.

Durum alanları yalnızca yukarıdaki değerleri kabul eder; kendi sisteminizdeki durum adlarını gönderirken bu değerlere dönüştürün.

Sipariş verisinde delivered, returned ya da cancelled durumuyla gelen satırlar için Sayproof bir teslimat kaydı oluşturur; bu durumda teslimat endpoint’ine ayrıca istek göndermeniz gerekmez.

İade ve iptal bilgisi yorumdan sonra da önemlidir. Siparişin ödemesi refunded ya da voided durumuna geçtiğinde ya da bir satır returned olarak bildirildiğinde, o siparişe ya da satıra daha önce yazılmış yorumların satın alma kanıtına “Yorumdan sonra iade edildi” işareti düşer ve otomatik kontroller yeniden çalışır. Alışveriş deneyimi davetiyle yazılmış yorumlar zaten iptal ya da iade sonrasında yazıldığı için bu işareti almaz. İptal ya da iade edilen ve henüz yorumlanmamış satırlar için alışveriş deneyimi daveti oluşturulur; bkz. Davetler ve e-postalar.

{ "accepted": 1, "orders": [{ "external_id": "ORD-1001", "id": "…" }] }

Liste bütün olarak işlenir: siparişlerden biri reddedilirse aynı istekteki diğer siparişler de kaydedilmez. Hata yanıtındaki kod, sorunlu alanı belirtir.

Sipariş verisiyle birlikte gönderilmeyen teslimat değişiklikleri için:

{
"deliveries": [
{
"external_id": "ORD-1001",
"line_reference": "1",
"state": "delivered",
"observed_at": "2026-09-27T09:00:00+03:00",
"source": "carrier"
}
]
}
Alan Zorunlu Açıklama
external_id, line_reference Evet Hangi siparişin hangi satırı olduğu.
state Evet Sipariş satırıyla aynı değerler.
observed_at Evet Durumun gözlendiği zaman; saat dilimiyle birlikte.
source Hayır platform (varsayılan), carrier, manual, estimated.
confidence Hayır verified (varsayılan) ya da estimated.
detail Hayır Kabul edilir ama saklanmaz; teslim alan kişinin adı ya da adres gibi bilgi göndermeyin.

Tahmine dayalı bilgi (estimated kaynak ya da güven değeri) kanıt sayılmaz; “kargo 3 günde teslim eder” gibi bir tahmin davet ya da yorum hakkı oluşturmaz. Tahmine dayalı bir delivered bilgisi satırın durumunu da belirlemez: kayıtlı kalır ancak daha önce ya da sonra gelen doğrulanmış teslimat bilgisini gizlemez. Yalnızca gerçekleştiği doğrulanan teslimat bilgisini gönderin.

Tanınmayan satırlar isteğin başarısız olmasına neden olmaz; yanıttaki unknown listesinde döner:

{ "accepted": 1, "unknown": [{ "external_id": "ORD-9", "line": "2" }] }
Yanıt Anlamı
401 refused / unknown_key Sunucu anahtarı tanınmıyor. Biçimi hatalı anahtarda ayrıntı malformed_key olur. Anahtarın tamamının Bearer önekinden sonra gönderildiğini kontrol edin.
401 refused / revoked_key Sunucu anahtarı iptal edilmiş. Yeni bir sunucu anahtarı oluşturun.
403 refused / scope_missing Anahtarın sipariş gönderme (orders) izni yok.
401 signature_refused / signature_mismatch İmzalı gönderimde imza eşleşmiyor. Body’nin imzalandıktan sonra değişip değişmediğini ve doğru şifrenin kullanıldığını kontrol edin.
401 signature_refused / timestamp_outside_window Zaman farkı 5 dakikadan fazla. Sunucu saatini senkronize edin.
401 signature_refused / timestamp_invalid Zaman değeri okunamadı ya da saat dilimi içermiyor.
401 signature_refused / secret_unknown Şifre kimliği tanınmıyor ya da şifre iptal edilmiş. Özel amaçlı şifreler (bildirim adresi, e-posta teslim bildirimi) sipariş aktarımını imzalayamaz. İstekte Authorization: Bearer header’ı yoksa istek imzalı gönderim sayıldığı için de bu yanıt döner.
400 invalid / field_missing: <alan> Zorunlu bir alan eksik. field_invalid ve field_too_long biçim ve uzunluk hatalarını bildirir.
400 invalid / market_without_policy: <pazar> Bu pazar için tanımlı kural yok.
400 invalid / status_unmapped: …/<değer> Durum değeri tanınmıyor. Yukarıdaki değerlerden birini gönderin.
400 invalid / channel_unknown Kanal kodu yanlış ya da kanal kapalı.
400 invalid / market_channel_mismatch: <pazar> Siparişin pazarı, siparişin bağlandığı kanalın pazarıyla aynı değil.
400 invalid / batch_too_large: 100 Tek istekte 100’den fazla sipariş gönderildi.
429 rate_limited Sunucu anahtarı ya da şifre başına 5 dakikada 600 istek sınırı aşıldı.

Paneldeki Entegrasyon › Sipariş aktarımı sekmesinin Mağazadan gönderim bölümündeki Bağlantıyı dene işlemi, mağaza sisteminizin göndereceği veriyi kaydetmeden sınar. Formda yalnızca Ne gönderilecek? (Sipariş ya da Teslimat) seçilir ve Gönderilecek içerik girilir; anahtar ya da şifre istenmez. Sonuç, verinin kabul edilip edilmediğini ve kaç kaydın kabul edileceğini gösterir; hiçbir kayıt oluşturulmaz.

Aynı kartta Son gelen siparişler satırı seçilen kanala gelen siparişleri sayar. Sipariş aktarımı durumu (tüm kanallar) bölümündeki son 7 günün istek sayıları ve Son istekler listesi ise bütün kanalları kapsar.