# Davetlerin kendi sisteminizden gönderilmesi

> Davet e-postalarının ve ret bildirimlerinin Sayproof yerine kendi e-posta sisteminizden gönderilmesi.

Kaynak: /tr/integrate/own-sending/

Varsayılan olarak davet e-postalarını Sayproof sizin adınıza gönderir. E-postaların kendi sisteminizden (CRM, e-posta hizmeti, pazarlama otomasyonu) gönderilmesini istiyorsanız Sayproof e-posta göndermez. Bunun yerine her davet için sisteminize imzalı bir HTTP isteği (webhook) gönderir ve e-postayı sizin sisteminiz gönderir.

Davet e-postası hiç gönderilmesin, müşteri yorumunu mağazanızın sipariş detayı sayfasında yazsın istiyorsanız bkz. [Davet e-postası olmadan](/tr/features/invitations.md#davet-e-postasi-olmadan).

Zamanlama kuralları değişmez: bekleme süresi, gönderim saatleri, günlük sınır, hatırlatma ve e-posta almak istemeyen müşteriler Sayproof tarafında denetlenir. Sisteminize ulaşan her istek, gönderilmesi gereken bir e-postayı temsil eder.

## Kurulum

1. **Kanallar** ekranının **Anahtarlar** sekmesinde **Gelişmiş: imzalı gönderim şifreleri** bölümünü açıp **Bildirim adresi şifresi oluştur** düğmesine basın. Şifre yalnızca bir kez gösterilir; kopyalayıp sisteminizde saklayın. Bu şifre yalnızca bu amaçla kullanılır ve sipariş aktarımını imzalayamaz.
2. **Davet gönderimi › Gönderim yolu** bölümünde **Kendi sistemimiz gönderir** seçeneğini işaretleyin.
3. **Bildirim adresi** alanına sisteminizdeki endpoint'in `https` adresini girin (en fazla 500 karakter).

Şifre ya da adres eksikse ayar kaydedilmez. Gönderim yolu ve bildirim adresi yalnızca panelde oturum açmış bir kullanıcı tarafından değiştirilebilir; bir API anahtarıyla yapılan değişiklik isteği `403 refused / panel_session_required` yanıtı alır.

## İstek

```http
POST https://crm.markaniz.com/sayproof/bildirim
Content-Type: application/json
User-Agent: sayproof-webhook
X-Sayproof-Timestamp: 2026-09-28T07:30:00.123456+00:00
X-Sayproof-Event-Id: 7d0c2f3e-…
X-Sayproof-Signature: 5f1a…
```

```json
{
  "address": "ayse@ornek.com",
  "context": {
    "brand": "Markanız",
    "channel": "web",
    "landing_url": "https://www.markaniz.com/yorum-yaz",
    "line_references": ["1"],
    "order_reference": "ORD-1001"
  },
  "event_id": "7d0c2f3e-…",
  "language": "tr",
  "message_class": "transactional",
  "subject": "Siparişiniz nasıldı?",
  "template_key": "default",
  "text": "…",
  "token": "sp_…"
}
```

| Alan | Anlamı |
|---|---|
| `address` | Alıcının e-posta adresi |
| `subject` | Konu satırı. Hatırlatmalarda başına "Hatırlatma: " eklenir. |
| `text` | E-postanın düz metin içeriği; yorum bağlantısını ve e-posta almak istememe bağlantısını içerir |
| `token` | Yorum bağlantısında kullanılan token |
| `context.landing_url` | Davet bağlantısının açacağı sayfa |
| `context.channel`, `context.brand` | Siparişin geldiği kanalın kodu ve e-postada kullanılacak marka adı (kanalın **Müşteriye görünen ad**ı, boşsa markanın adı). Kanallarınız müşteriye farklı adlarla görünüyorsa e-postanın tasarımını bu alanlara göre seçin. |
| `context.order_reference`, `context.line_references` | Davetin ait olduğu sipariş ve sipariş satırları |
| `language` | `tr` ya da `en` |
| `message_class` | `transactional` (işlem e-postası) |
| `template_key` | Kullanılan davet e-postasının anahtarı; ret bildirimlerinde `rejection:<gerekçe>` |
| `event_id` | İsteğin kimliği; `X-Sayproof-Event-Id` header'ıyla aynıdır |

Kendi e-posta tasarımınızı kullanıyorsanız yorum bağlantısını, `landing_url` adresinin sonuna `#review_token=` ve `token` değerini ekleyerek oluşturun:

```text
https://www.markaniz.com/yorum-yaz#review_token=sp_…
```

Token adresin `#` işaretinden sonraki bölümünde durduğu için tarayıcı onu sunucuya göndermez ve analiz araçlarının kaydettiği sayfa adresine girmez. Script, eski biçimdeki `?review_token=sp_…` bağlantılarını da okur. `text` içindeki bağlantı bu biçimde hazırlanmıştır.

`text` içindeki e-posta almak istememe bağlantısı e-postanızda mutlaka yer almalıdır.

İptal ya da iade edilen satırlar için oluşturulan alışveriş deneyimi davetleri de aynı biçimde iletilir; konu satırı ve metin bu davete göre hazırlanır. Bkz. [Davetler ve e-postalar](/tr/features/invitations.md#iptal-ve-iade-sonrasi-surec-daveti).

### Ret bildirimleri

Moderatörün reddettiği yorumun sahibine gönderilecek bildirim de aynı adrese iletilir. Bu isteklerde `template_key` `rejection:<gerekçe>` biçimindedir, `context` boştur ve `text` ret gerekçesini ve düzeltme bağlantısını içerir. Ret bildirimi bir hizmet bildirimidir ve gecikmeden gönderilmelidir. Metni değiştirmeyin: Reklam Kurulunun **Tüketici Değerlendirmeleri Hakkında Kılavuzu**, ret bildiriminde tüketicinin değerlendirmesini değiştirmeye yönlendirilmesini manipülatif uygulama olarak kabul eder.

## İmzanın doğrulanması

İmza, sipariş aktarımındakiyle aynı biçimdedir ancak **Bildirim adresi şifresi** ile hesaplanır, imzalı gönderim şifresiyle değil: `hex(HMAC-SHA256(şifre, zaman + "." + body))`. Body'yi ham byte olarak okuyun; JSON'u ayrıştırıp yeniden metne dönüştürürseniz imza eşleşmez.

```js
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";

const app = express();

app.post("/sayproof/bildirim", express.raw({ type: "application/json" }), (request, response) => {
  const timestamp = request.get("X-Sayproof-Timestamp") ?? "";
  const given = Buffer.from(request.get("X-Sayproof-Signature") ?? "");
  const expected = Buffer.from(
    createHmac("sha256", process.env.SAYPROOF_NOTICE_SECRET).update(`${timestamp}.`).update(request.body).digest("hex")
  );
  const fresh = Math.abs(Date.now() - Date.parse(timestamp)) < 5 * 60 * 1000;
  if (!fresh || given.length !== expected.length || !timingSafeEqual(given, expected)) {
    return response.sendStatus(401);
  }
  queueEmail(JSON.parse(request.body.toString("utf-8")));
  response.sendStatus(202);
});
```

## Yanıt ve yeniden deneme

- Her `2xx` yanıtı başarılı sayılır; yanıtın body'si okunmaz. **10 saniye** içinde yanıt verin; e-postanın gönderimini arka planda yapın.
- `5xx`, `408` ve `429` yanıtları, zaman aşımı ve bağlantı hataları geçici sayılır: gönderim yarım saat, 1 saat, 2 saat ve 4 saat sonra yeniden denenir. Beşinci denemede de başarısız olursa davetin durumu "Gönderilemedi" olur. Ret bildirimleri de aynı aralıklarla yeniden denenir.
- Diğer `4xx` yanıtlarında ve adres kurallara uymadığında davet beklemeden "Gönderilemedi" olur.
- Her deneme ayrı bir gönderim kaydıdır ve yeni bir `event_id` taşır. Sisteminiz isteği aldığı hâlde yanıt süresi dolduysa aynı davet yeniden gelebilir; tekrarları `token` değeriyle ayıklayın. Hatırlatma da aynı `token` değerini taşır ve konu satırının başındaki "Hatırlatma: " önekiyle ayırt edilir.
- Adres `https` olmalı ve internete açık bir IP adresine çözümlenmelidir. Yönlendirmeler (redirect) izlenmez.
- Adres varsayılan `https` portunu kullanmalıdır; adreste port numarası varsa (`:8443` gibi) istek gönderilmez ve gönderim kaydına `port_refused` yazılır.

Her gönderim **Mesaj kayıtları** ekranına kaydedilir. Başarısız gönderimlerin nedeni (örneğin `http_status: 503`) ayrıntı bölümünde gösterilir. Sisteminiz düzeldikten sonra "Gönderilemedi" durumundaki davetler **Davetler** ekranındaki **Gönderilemeyenleri yeniden dene** düğmesiyle yeniden gönderilebilir; aynı `token` değeriyle yeni bir `event_id` taşırlar. Bağlantısının süresi dolmuş davetler atlanır ([Davetler](/tr/features/invitations.md#davetler)).

## Sorumluluklarınız

- E-postayı `address` adresine, istekteki konu satırı ve içerikle gönderin.
- E-postaya kupon, indirim, ürün önerisi ya da kampanya eklemeyin. Davet bir işlem e-postasıdır ve bu nedenle müşterinin ayrıca onay vermesini gerektirmez; tanıtım içeriği eklendiğinde ticari elektronik ileti niteliği kazanır.
- E-posta almak istememe bağlantısını kaldırmayın.
- Ret bildirimlerini de gönderin.
