İçeriğe geç

Storefront API

Markdown

Mağaza sayfasının ve mağaza sunucusunun istek gönderdiği endpoint'ler.

Sürüm v1. Endpoint yollarının başına eklenecek Sayproof API adresi panelde Entegrasyon ekranında gösterilir.

Çağıran Yöntem
Tarayıcı (mağaza sayfası) Site anahtarı: okuma isteklerinde ?key= parametresi, yazma isteklerinde X-Sayproof-Site-Key header’ı. İstek doğrulanmış bir alan adından gelmelidir: alan adı Origin header’ından, Origin yoksa Referer header’ından okunur.
Mağaza sunucusu Authorization: Bearer <sunucu anahtarı> header’ı ve ?channel=<kanal kodu> parametresi

Hiçbir endpoint tarayıcı oturumunu (cookie) kullanmaz; istekler cookie olmadan gönderilir.

  • İstek ve yanıt body’leri JSON biçimindedir.
  • Hata yanıtının biçimi tüm endpoint’lerde aynıdır: {"error": "<kod>", "detail": "<kod>"}. detail de bir cümle değil, koddur; kullanıcıya gösterilecek metne kendi tarafınızda dönüştürülür. Kodların listesi için: Hata kodları.
  • Dil sırasıyla body’deki language alanından (yazma istekleri), ?lang=tr|en parametresinden ya da kanalın dilinden belirlenir. Accept-Language header’ı dikkate alınmaz. Desteklenmeyen bir dil istenirse kanalın dili kullanılır.
  • Her yanıt X-Request-Id header’ını taşır; destek talebinde bu değeri iletin.
  • Anahtar, kanal ya da alan adıyla ilgili sorunlarda 403 refused yanıtı döner ve detail nedeni belirtir (örneğin origin_unverified: www.markaniz.com, unknown_site_key, channel_inactive). origin_unverified ayrıntısı isteğin geldiği alan adını taşır. Rate limit aşıldığında 429 rate_limited döner.

GET /v1/reviews/list — yayındaki yorumları, özeti ve zorunlu öğeleri döndürür.

Parametre Varsayılan Kural
key Site anahtarı
product Zorunlu; en fazla 128 karakter
scope variant variant ya da group
sort Pazarın varsayılanı İzin verilen liste dışındaki değer 400 sort_not_allowed yanıtı alır
page, page_size 1, 10 page 1–1000, page_size 1–50; aralık dışındaki değerler en yakın sınıra çekilir
rating 1–5; aralık dışındaki değer 400 invalid / rating yanıtı alır
verified 1: yalnızca satın alma kanıtı olan yorumlar
media 1: yalnızca fotoğraf ya da video içeren yorumlar
q Başlık ve metinde arama; en fazla 100 karakter. Tüm kelimeler geçmelidir. Büyük/küçük harf ve ı/i farkı dikkate alınmaz.
topic Tek kelime (en fazla 40 harf); bu kelimeyle başlayan bir kelime içeren yorumlar (rahat → rahatlık)
lang Kanalın dili tr ya da en
via Script script gönderir. Yorumları kendi kodunuzla okuyorsanız göndermeyin; panelin Mağaza görünümü ekranı bu sayfaları sitenizin kendi tasarımı olarak sayar.

Yanıt:

{
"reviews": [
{
"id": "…", "rating": 5, "title": "…", "body": "…", "author": "Ayşe K.", "anonymous": false,
"language": "tr", "published_at": "…", "verified": true, "verification_method": "tokenized_invite",
"helpful_count": 3, "unhelpful_count": 1,
"aspects": [{ "key": "size", "label": "Beden", "scale": "fit", "value": 2, "position": 0.5, "step_label": "Yeterli" }],
"aspect_scores": { "size": 2 }, "aspect_template": "footwear",
"media": [{ "id": "…", "kind": "image", "url": "…", "srcset": "… 320w, … 640w, … 1280w", "width": 1280, "height": 960, "alt_text": "", "poster_url": "" }],
"seller_response": { "body": "…", "published_at": "…" },
"resolution": { "body": "…", "created_at": "…" },
"origin": "own", "origin_market": "", "experience": "product", "translations": {}
}
],
"total": 200, "page": 1, "pages": 20, "page_size": 10, "sort": "date", "shared": 0,
"ai_summary": null,
"sorts": [{ "code": "date", "label": "En yeni" }, { "code": "rating", "label": "Puana göre" }, { "code": "seller", "label": "Satıcı yanıtı olanlar" }],
"aggregate": { "count": 200, "average": 4.1, "stars_filled": 4, "distribution": { "1": 5, "5": 120 }, "verified_count": 200 },
"aspects": [{ "key": "size", "label": "Beden", "scale": "fit", "steps": ["Düşük", "Yeterli", "Yüksek"], "average": 2.1, "position": 0.55, "step_label": "Yeterli", "count": 48 }],
"topics": [{ "word": "rahat", "count": 31 }],
"gallery": [{ "id": "…", "kind": "image", "url": "…", "srcset": "…", "width": 1280, "height": 960, "alt_text": "", "poster_url": "", "review_id": "…", "rating": 5, "author": "Ayşe K.", "anonymous": false }],
"media_reviews": 14, "style": "cards", "theme": "warm",
"applied": { "q": "", "topic": "", "rating": null, "media": false, "verified": false },
"core": {
"method_statement": { "url": "…", "label": "Yorumları nasıl topluyoruz", "required": true },
"sort": { "allowed": ["date", "rating", "seller"], "default": "date", "locked": true },
"verification_badge": { "label": "Doğrulanmış alıcı", "required": true },
"source_label_required": true, "streams_together": true, "resolution_inline": true,
"aggregate": { "…": "…" }, "policy_version": 1, "market": "TR"
},
"language": "tr",
"words": { "verified": "Doğrulanmış alıcı", "…": "…" },
"report_reasons": [{ "code": "suspected_fake", "label": "…" }],
"questions_enabled": false,
"privacy_url": "https://markaniz.com/kvkk-aydinlatma-metni",
"limits": { "media_count": 6, "title_length": 200, "body_length": 5000, "name_length": 120, "alt_text_length": 300, "image_bytes": 12582912, "video_bytes": 209715200, "video_seconds": 60, "reviews_per_call": 20, "order_reference_length": 128, "email_length": 254, "report_note_length": 1000 }
}
  • aggregate.stars_filled: dolu yıldız sayısı; yarım değerler yukarı yuvarlanır (4,5 → 5).
  • aspects (üst düzey): basamaklı ölçekli değerlendirme başlıklarının ortalamaları. position 0 ile 1 arasındadır, step_label en yakın basamağın etiketidir. Filtreler bu değerleri değiştirmez.
  • topics: yorumlarda en sık geçen en fazla 5 kelime ve her birinin kaç yorumda geçtiği. Kelimeler en az 4 harfli olmalı ve en az 2 yorumda geçmelidir; değerler doğrudan topic parametresinde kullanılabilir.
  • gallery: ürünün yayındaki yorumlarına eklenmiş ve işlenmesi tamamlanmış en fazla 12 fotoğraf ya da video; en yeni yorumdan başlar. Her öğe media alanlarını ve ait olduğu yorumun review_id, rating, author ve anonymous değerlerini taşır. Filtreler bu listeyi değiştirmez.
  • media_reviews: fotoğraf ya da video içeren yayındaki yorum sayısı; media=1 filtresinin tek başına döndürdüğü yorum sayısıdır. Filtreler bu değeri değiştirmez.
  • style: kanalın panelde seçilen düzeni, cards ya da sidebar.
  • theme: kanalın panelde seçilen tasarımı: warm, trust, editorial, minimal, soft, bold, natural ya da night.
  • applied: uygulanan filtreler.
  • experience: product (ürün yorumu) ya da process (siparişi iptal edilen ya da ürünü iade eden müşterinin o aşamaya kadarki deneyimi). process yorumları words.experience_process etiketiyle gösterilmelidir; varsayılan bileşen bu etiketi kendisi gösterir.
  • limits: yorum formunun uyguladığı sınırlar: dosya sayısı (media_count), metin uzunlukları (title_length, body_length, name_length, alt_text_length), dosya boyutları byte olarak (image_bytes, video_bytes), video süresi saniye olarak (video_seconds), tek istekteki ürün sayısı (reviews_per_call), sipariş numarası ve e-posta uzunluğu (order_reference_length, email_length) ve bildirim notu uzunluğu (report_note_length).
  • core.method_statement.url: isteğin kanalı ve dili için geçerli yöntem beyanının adresi (kanal için bağlanan kendi sayfanız ya da Sayproof’un sayfası).
  • Yanıt Cache-Control: private, max-age=30 header’ını taşır.
  • questions_enabled: markanın soru-cevabı açık mı; ayrıntılar için Soru-cevap.
  • privacy_url: isteğin kanalında panelde girilen aydınlatma metni bağlantısı; girilmemişse boş. Script bu adresi yorum, soru ve cevap formlarının altında Kişisel verilerin işlenmesi hakkında aydınlatma metni bağlantısı olarak gösterir (words.privacy_notice).
  • origin, origin_market: own markanın bu pazardaki yorumudur. Markanızda pazarlar arası paylaşım açıksa (Ayarlar › Yayınlama › Diğer pazarlardan yorumlar) liste aynı ürünün diğer pazarlarınızdaki satın alma kanıtlı yorumlarını da taşır: bu satırlarda origin syndicated, origin_market geldiği pazardır. Bu yorumlar ortalamaya, puan dağılımına ve yapılandırılmış veriye girmez; shared listede kaç tane olduklarını söyler.
  • origin_label, origin_url: kaynağı own olmayan her yorumda hazır etiket metni (sunucu, ziyaretçinin dilinde ve doğru Türkçe ekleriyle yazar; script yalnız gösterir). Pazaryerinden aktarılmış yorumda (origin: "imported") etiket “Trendyol’da satın alındı · Trendyol’dan otomatik aktarıldı” gibidir, origin_url kaynaktaki yorumun adresidir (yoksa boş) ve verified her zaman false, verification_method boştur. Bu yorumlar verified_only süzgecine girmez, ortalamaya, puan dağılımına ve yorum sayısına katılır, yapılandırılmış veriye ve Google ürün yorumu dosyasına girmez. Ayrıntılar için Pazaryeri yorumları.
  • aggregate.imported_count, aggregate.imported_label: aktarılmış yorum sayısı ve özet satırının hazır metni (“4 yorumun 3’ü Trendyol’dan”); aktarılmış yorum yoksa 0 ve boş metin. aggregate.verified_count aktarılmış yorumları saymaz.
  • translations (v2 ile gelecek; şu an her yorumda boş nesne {} döner): yapay zekâ paketinde çeviri açıksa yorumun diğer dillerdeki çevirileri, dil koduna göre {"en": {"title", "body"}}. Script, yorum ziyaretçinin dilinde değilse çeviriyi gösterir ve aslını gösterme bağlantısı ekler.
  • ai_summary (v2 ile gelecek; şu an her zaman null döner): yapay zekâ paketinde yorum özeti açıksa ve ürünün yeterli yorumu varsa özet: text, dayandığı yorum sayısı (review_count), oluşturulma zamanı (created_at) ve öne çıkan konular (topics[]: topic, sentiment, count); yoksa null. Varsayılan bileşen özeti etiketiyle birlikte gösterir; özet bölümü gizlenemez.

GET /v1/ssr — hazır HTML’i, liste yanıtıyla aynı içerikteki state alanını ve yapılandırılmış veriyi döndürür. Parametreler: product, channel, scope, name, lang, sort, style (cards ya da sidebar; başka bir değer 400 invalid / style yanıtı alır), theme (warm, trust, editorial, minimal, soft, bold, natural ya da night; başka bir değer 400 invalid / theme yanıtı alır). Kullanım ve yanıt alanları için: Server-side rendering (SSR).

  • Yanıt ETag ve Cache-Control header’larını taşır: sunucu anahtarıyla gönderilen istekte private, max-age=60, site anahtarıyla gönderilen istekte public, max-age=60. If-None-Match ile gönderilen istekte içerik değişmemişse 304 döner.
  • Kanalın kullanımda bir site anahtarı yoksa 409 refused / no_site_key döner.

GET /v1/viewer — yalnızca sunucu anahtarıyla kullanılabilir. Müşterinin e-posta adresi X-Sayproof-Customer header’ında gönderilir. Parametreler: product, scope, lang, channel. Yanıttaki state değeri can_write, written ya da none olur; yanıt ayrıca reviews, limits, müşteri yorum yazabiliyorsa token ile products ve marka soru-cevabı açtıysa asker (token, name) alanlarını içerir. Soruyla gösterilecek ad isteğe bağlı X-Sayproof-Customer-Name header’ıyla, UTF-8 percent-encode edilerek gönderilir. Yanıt Cache-Control: no-store header’ını taşır. Ayrıntılar için: Oturum açmış müşteri.

GET /v1/viewer/order — oturum açmış müşterinin sipariş detayı sayfası için siparişin ürünlerini ve her birinin yorum durumunu döndürür. Yalnızca sunucu anahtarıyla kullanılabilir; tarayıcıdan site anahtarıyla gönderilen istek 403 refused / server_only yanıtı alır. Müşterinin e-posta adresi X-Sayproof-Customer header’ında gönderilir. Parametreler: order (sipariş numarası, en fazla 128 karakter), channel, lang.

{
"order": "100245",
"token": "…",
"lines": [
{ "line_reference": "1", "variant_key": "URUN-38", "group_key": "URUN", "title": "Koşu ayakkabısı", "aspects": [{ "key": "size", "label": "Beden", "kind": "product", "required": false, "scale": "fit", "steps": ["Düşük", "Yeterli", "Yüksek"] }], "state": "can_write" },
{ "line_reference": "2", "variant_key": "CORAP-2", "group_key": "CORAP", "title": "Koşu çorabı", "aspects": [], "state": "pending", "rating": 4 }
],
"limits": { "media_count": 6, "body_length": 5000, "…": "…" },
"language": "tr",
"theme": "warm",
"privacy_url": "https://markaniz.com/kvkk-aydinlatma-metni",
"words": { "order_title": "Ürünleri değerlendirin", "…": "…" }
}
  • lines[].state: can_write, pending, published, rejected, removed, waiting ya da closed. Anlamları için: Oturum açmış müşteri › Sipariş detayı sayfası.
  • privacy_url: kanalın aydınlatma metni bağlantısı; girilmemişse boş. Script bağlantıyı formların altında gösterir.
  • token: yorum yazılabilen satırlar için tek bir yazma token’ı; yazılabilen satır yoksa boş. aspects yalnızca can_write satırlarında dolu gelir; rating yalnızca yorumu yazılmış satırlarda bulunur.
  • Sipariş bulunamazsa ya da başka bir müşteriye aitse yanıt yine 200 olur ve lines boş döner; yanıttan siparişin var olup olmadığı anlaşılmaz.
  • order gönderilmezse 400 invalid / order, X-Sayproof-Customer header’ı eksikse ya da geçerli bir adres değilse 400 invalid / customer döner.
  • Yanıt Cache-Control: no-store header’ını taşır. Rate limit GET /v1/viewer ile ortaktır.

POST /v1/reviews/<id>/helpful — body: {"vote": "up" | "down" | "none", "visitor_key": "…"}.

{ "vote": "down", "counted": true, "helpful_count": 3, "unhelpful_count": 1 }
  • Her ziyaretçi bir yorum için tek oy verebilir. Aynı yönde yeniden oy verilirse counted: false döner; yön değiştirilirse oy yeni yöne taşınır; none oyu geri alır (vote: null).
  • visitor_key yalnızca tekrarları ayıklamak için kullanılır; rate limit IP adresine göre uygulanır.

POST /v1/reviews/<id>/report — body: {"reason": "…", "note": "…", "visitor_key": "…"}. Gerekçe, liste yanıtındaki report_reasons alanından seçilir; liste dışındaki değer 400 invalid_reason yanıtı alır. Not en fazla 1000 karakter olabilir. Başarılı istekte 201 {"id"} döner. Yalnızca yayındaki yorumlar bildirilebilir. Aynı ziyaretçinin (visitor_key, gönderilmezse IP adresi) aynı yoruma ilişkin açık bir bildirimi varsa yeni kayıt oluşturulmaz; yanıt mevcut bildirimin id değerini döndürür.

POST /v1/views?key=… — body, text/plain içerik türüyle gönderilen JSON’dur: {"product": "…", "scope": "variant" | "group"}. Script ayrıca yorumların nasıl gösterildiğini de bildirir: shown (default varsayılan bileşen, coded görünümü kodda seçilmiş, headless), kodda seçildiyse style ve theme, ve yorum alanının piksel genişliği width. Sayproof genişliği yalnızca dört aralıktan birine çevirerek saklar; bu alanlar yoksa ya da geçersizse yalnızca görüntülenme sayılır. Başarılı istekte body içermeyen 204 döner. Script bu isteği kendisi gönderir; headless kullanımda da script sayfada yüklü olduğu sürece ayrıca göndermeniz gerekmez. Otomatik istemcilerden (bot, bağlantı önizleme aracı) ve önceden yükleme (prefetch) isteklerinden gelen görüntülenmeler sayılmaz. Uygulama içi tarayıcılar (örneğin Pinterest, Telegram, Slack, Discord) ve adında “bot” geçen CUBOT gibi telefon markaları sayılır. Önceden hazırlanan (prerender) bir sayfada script, görüntülenmeyi sayfa gerçekten gösterildiğinde bildirir.

GET /v1/method-statement?key=…&lang=tr|en — herkese açık sayfa; alan adı doğrulaması gerektirmez (yeni sekmede açılır). format=json parametresiyle makine tarafından okunabilir biçimde döner. Sayfa, site anahtarının kanalına ait beyanı gösterir; metin o kanalın kurallarından ve yayınlama yönteminden hazırlanır ve panelde o kanal için gösterilen metinle aynıdır.

Aşağıdaki endpoint’leri script kullanır. Yorum yazma akışı headless kullanımda da script’te kaldığı için bu endpoint’lere doğrudan istek göndermeniz gerekmez.

Endpoint İşlevi
POST /v1/eligibility Sipariş numarası ve e-posta adresiyle uygunluğu denetler. Müşteri uygunsa tek kullanımlık bir yazma token’ı döner; değilse tek ve genel bir ret yanıtı döner.
POST /v1/eligibility/token Davet, alışveriş deneyimi daveti ya da düzeltme bağlantısındaki token’ı doğrular. Yanıttaki mode değeri write, feedback ya da revise olur. feedback yanıtındaki ürünler değerlendirme başlığı içermez. revise yanıtı düzeltilecek yorumu, yazanın girdiği adı (review.author_name), adın sitede gizlenip gizlenmediğini (review.hide_name) ve yoruma ekli dosyaları (review.media: id, kind) içerir. Bağlantı başka bir pazarın kanalında açılırsa 403 token_refused / token_foreign_market döner.
POST /v1/media Fotoğraf ya da video yükler (jpeg, png, webp: en fazla 12 MB; mp4, mov: en fazla 200 MB ve 60 saniye). Dosya güvenlik taramasından geçirilir; konum ve cihaz bilgileri silinir. Süresi sınırı aşan video yüklenirken reddedilir: 422 refused / video_too_long: 60. 3840×2160’tan (dikeyde 2160×3840) büyük, saniyede 60 kareden fazla ya da H.264, HEVC, MPEG-4, VP9, AV1 dışında kodlanmış video da reddedilir. Yanıt dosyanın adresini taşımaz; dosya ancak eklendiği yorum yayındayken herkese açık adreste durur.
POST /v1/reviews Yorumları gönderir (bir istekte en fazla 20 ürün). Ürün daveti ve alışveriş deneyimi daveti token’larını kabul eder; alışveriş deneyimi daveti token’ıyla yazılan yorum experience: "process" olarak kaydedilir. Her satır isteğe bağlı author_name (en fazla 120 karakter) ve hide_name (true ya da false; varsayılan false) alanlarını taşıyabilir. hide_name: true olduğunda ad sitede, yapılandırılmış veride ve Google dosyasında her sözcüğün ilk harfi ile *** olarak görünür (Ayşe Kaya yerine A*** K***); adın tamamı yalnızca markanın panelinde görünür. hide_name mantıksal değer değilse 400 invalid / hide_name döner.
POST /v1/reviews/revise Reddedilen yorumu düzeltilmiş hâliyle yeniden gönderir. Body’deki kept_media, yorumda kalacak mevcut dosyaların kimlik listesidir; alan gönderilmezse mevcut dosyaların hepsi kalır. Kalan ve yeni eklenen dosyalar birlikte en fazla 6 olabilir. author_name ve hide_name gönderilirse yorumdaki değerlerin yerine geçer (boş author_name adı siler); gönderilmezse mevcut değerler korunur.

Rate limit değerleri için: Limitler.

Marka panelde Ayarlar › Yayınlama › Soru-cevap seçeneğini açtığında kullanılabilir; kapalıyken üç endpoint de 403 refused / questions_disabled döner ve liste yanıtındaki questions_enabled değeri false olur. Script bölümü yalnızca bu değer true iken yükler.

Endpoint İşlevi
GET /v1/questions Ürünün yayındaki sorularını ve her sorunun yayındaki cevaplarını döndürür. Parametreler: key, product (zorunlu), scope (variant ya da group), page (1–1000), page_size (varsayılan 5, en fazla 20), lang. Sunucu anahtarıyla channel parametresiyle de okunabilir.
POST /v1/questions Ziyaretçinin sorusunu kaydeder. Body: product, scope, name (isteğe bağlı, en fazla 120 karakter), email (isteğe bağlı; yoksa cevap geldiğinde e-posta gitmez), body (zorunlu, en fazla 1000 karakter), hide_name (isteğe bağlı mantıksal değer; true ise ad sitede her sözcüğün ilk harfi ile *** olarak görünür), language. Oturum açmış müşteride name ve email yerine GET /v1/viewer yanıtındaki asker.token değeri asker alanında gönderilir; ad ve e-posta adresi token’dan okunur. Satın alma gerekmez. Başarılı istekte 201 {"id", "state"} döner.
POST /v1/questions/<id>/answers Ürünü satın almış müşterinin cevabını kaydeder. Yazma token’ı X-Sayproof-Token header’ında gönderilir; davet ya da sipariş doğrulamasıyla alınan token geçerlidir, yorum yazmak için kullanılmış olması cevap yazmayı engellemez. Body: body (zorunlu, en fazla 2000 karakter), name (isteğe bağlı), hide_name (isteğe bağlı mantıksal değer; true ise ad sitede her sözcüğün ilk harfi ile *** olarak görünür), language. Başarılı istekte 201 {"id", "state"} döner.

GET /v1/questions yanıtı:

{
"questions": [
{
"id": "…", "author": "Deniz", "body": "Geniş ayağa uyar mı?", "published_at": "…",
"answers": [
{ "id": "…", "kind": "brand", "author": "Örnek Marka", "verified": false, "body": "…", "published_at": "…" },
{ "id": "…", "kind": "buyer", "author": "Ali", "verified": true, "body": "…", "published_at": "…" }
]
}
],
"total": 4, "page": 1, "pages": 1, "page_size": 5,
"limits": { "question_length": 1000, "answer_length": 2000, "name_length": 120, "email_length": 254 },
"language": "tr"
}
  • Sorular pazara göre birleştirilir: aynı pazardaki kanallarda sorulan sorular birlikte gösterilir. En yeni yayınlanan soru önce gelir; cevaplar yayına alınma sırasıyla listelenir.
  • kind: brand (markanın cevabı; author kanalın marka adıdır) ya da buyer (ürünü satın almış müşterinin cevabı; verified: true, “Doğrulanmış alıcı” etiketiyle gösterilir). Sorunun ve cevabın e-posta adresi yanıtta yer almaz.
  • Soru ve müşteri cevabı yayına çıkmadan önce onaylanır. Kişisel bilgi, küfür ya da sağlık iddiası içeren metin reddedilmez, onaya düşer. Yayınlama yöntemi Otomatik ya da Karma ise ve metin bu kontrollerden geçerse kendiliğinden yayınlanır.
  • Doğrulama eksikse 400 invalid döner ve detail alanı nedeni belirtir: body_required, body_too_long, email_invalid, email_too_long, name_too_long, asker_too_long, product_required, product_too_long.
  • asker token’ının süresi (1 saat) dolduysa 403 token_refused / asker_expired, token geçersizse ya da başka bir markaya aitse 403 token_refused / asker_invalid döner.
  • Token’ın siparişinde sorunun ürünü (aynı varyant ya da aynı ürün grubu) yoksa 403 token_refused / not_a_buyer döner. Token yoksa 401 token_required; soru yayında değilse ya da başka pazarınsa 404 not_found döner.
  • Cevap yayına çıktığında, soruda e-posta adresi varsa soruyu soran kişiye markanın adıyla bir e-posta gider. Adres, markanın e-posta almak istemeyenler listesindeyse e-posta gönderilmez.
  • GET /v1/questions yanıtı Cache-Control: private, max-age=30 header’ını taşır.

Yorum listesini komut satırından denemek (istek doğrulanmış bir alan adından geliyormuş gibi Origin header’ı eklenir):

Terminal window
curl -s "https://api.sayproof.example/v1/reviews/list?key=SITE-ANAHTARINIZ&product=URUN-38&sort=date&page=1&lang=tr" \
-H "Origin: https://www.markaniz.com"

Tarayıcıdan yorum bildirmek:

export async function reportReview(reviewId, reason, note) {
const answer = await fetch(`https://api.sayproof.example/v1/reviews/${encodeURIComponent(reviewId)}/report`, {
method: "POST",
credentials: "omit",
headers: { "Content-Type": "application/json", "X-Sayproof-Site-Key": "SITE-ANAHTARINIZ" },
body: JSON.stringify({ reason, note }),
});
if (answer.status === 201) return answer.json();
const problem = await answer.json().catch(() => ({}));
throw new Error(problem.detail || problem.error || `sayproof_report_${answer.status}`);
}