Rehberler

Webhook'lar

Bir şey olduğunda Ödecik, tanımladığın HTTPS adresine imzalı bir JSON isteği gönderir. Yoklama yapmana gerek kalmaz.

Endpoint tanımlama

Panelde Geliştirici → Webhook'lar bölümünden ya da POST /webhooks ile ekleyebilirsin. Oluşturma yanıtındaki secret (whsec_…) yalnızca bir kez gösterilir; imza doğrulamada kullanılır.

  • Adres https:// olmalı ve herkese açık bir sunucuya çözülmeli. IP adresi, localhost ve özel ağ adresleri kabul edilmez.
  • Yönlendirmeler (redirect) takip edilmez.
  • Yanıtın 6 saniye içinde 2xx dönmeli; işi kuyruğa alıp hemen yanıtla.

Olaylar

OlayNe zaman
order.createdSipariş oluştu (ödeme onaylandığı anda order.paid ile birlikte gelir).
order.paidÖdeme onaylandı; sipariş teslime hazır.
order.shippedKargo bilgisi girildi.
order.refundedSipariş iade edildi.
payout.completedBakiye talebin IBAN'a aktarıldı.

İstek biçimi

başlıklar
POST /odecik-webhook HTTP/1.1
Content-Type: application/json
User-Agent: Odecik-Webhooks/1.0
X-Odecik-Event: order.paid
X-Odecik-Delivery: evt_3f9a1c2b7d4e5f60a1b2
X-Odecik-Signature: t=1768473000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
gövde — order.paid
{
  "id": "evt_3f9a1c2b7d4e5f60a1b2",
  "event": "order.paid",
  "createdAt": "2026-01-15T10:30:00.000Z",
  "data": {
    "orderNo": "ODC-M2K9X1-A4F2",
    "status": "PAID",
    "totalKurus": 11920,
    "netKurus": 11503,
    "buyerEmail": "ayse@example.com",
    "items": [
      { "name": "Premium şablon paketi", "variant": null, "quantity": 1, "priceKurus": 14900 }
    ]
  }
}
data — order.shipped
{
  "orderNo": "ODC-M2K9X1-A4F2",
  "status": "SHIPPED",
  "carrier": "yurtici",
  "carrierName": "Yurtiçi Kargo",
  "trackingNo": "123456789012",
  "trackingUrl": "https://www.yurticikargo.com/…",
  "buyerEmail": "ayse@example.com"
}
data — order.refunded
{
  "orderNo": "ODC-M2K9X1-A4F2",
  "status": "REFUNDED",
  "totalKurus": 11920,
  "buyerEmail": "ayse@example.com"
}
data — payout.completed
{
  "payoutId": "cm9x2k1a30077",
  "amountKurus": 250000,
  "iban": "TR330006100519786457841326"
}

İmza doğrulama

Her istek X-Odecik-Signature: t=ZAMAN,v1=İMZA başlığıyla imzalanır. İmza, ZAMAN + "." + ham_gövde metninin secret ile HMAC-SHA256 hesaplanıp hex yazılmış halidir.

import crypto from "node:crypto";

// Express: app.post("/odecik-webhook", express.raw({ type: "application/json" }), handler)
export function verifyOdecik(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Yeniden deneme

2xx dışında yanıt veya zaman aşımı olursa teslimat 4 kez denenir: hemen, 5 saniye, 30 saniye ve 3 dakika sonra. 429 dışındaki 4xx yanıtlar kalıcı ret sayılır ve yeniden denenmez. Her deneme aynı id'yi taşır — bu değeri idempotentlik anahtarı olarak kullan ve aynı olayı iki kez işleme.

Teslimat geçmişini panelden ya da GET /webhooks/:id/deliveries ile görebilir, POST /webhooks/:id/test ile örnek olay gönderebilirsin.

Discord ve Slack

Endpoint adresi bir Discord veya Slack webhook adresiyse Ödecik olayı o platformun biçiminde, imzasız ve okunaklı bir mesaj olarak gönderir. Ayrıca bir sunucu yazmana gerek yoktur.

  1. Discord: kanal ayarları → Entegrasyonlar → Webhook'lar → yeni webhook → URL'yi kopyala.
  2. Slack: Incoming Webhooks uygulamasını ekle → kanal seç → URL'yi kopyala.
  3. Panelde Geliştirici → Discord veya Slack kanalına bildirim alanına yapıştır.
API ile
curl https://odecik.com/api/v1/webhooks \
  -X POST \
  -H "Authorization: Bearer $ODECIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://discord.com/api/webhooks/123456789/abcdef",
    "events": ["order.paid", "order.shipped", "order.refunded"]
  }'