Dit document is voorlopig alleen in het Turks beschikbaar.

Webhook

Mağazanda bir olay olunca adresine imzalı JSON gönderilir: sipariş, ürün, stok ve müşteri olayları. Abonelik oluşturma, imza doğrulama örnekleri, yeniden deneme kuralları ve olay gövdeleri.

Abonelik

Mağazam → Ayarlar → Geliştirici sayfasından ya da API'den açılır. Mağaza başına en çok 10 abonelik açılır, sınır aşılınca 422 döner. Adres herkese açık bir sunucuda olmalıdır; iç ağ ve localhost kabul edilmez.

Bir uygulama anahtarı yalnız kendi açtığı abonelikleri görür ve siler; uygulama kaldırılınca abonelikleri de silinir. Mağaza sınırı uygulamanın abonelikleriyle birlikte sayılır.

Yöntem ve adres Kapsam Ne yapar
GET /webhooks webhooks.read Abonelikleri, hata sayısını ve son gönderimi listeler
POST /webhooks webhooks.write Abonelik açar, imza anahtarını döner
DELETE /webhooks/{id} webhooks.write Siler, 204 döner
bash
curl -X POST "https://piyodo.com/api/store/v1/webhooks" \
  -H "Authorization: Bearer psk_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://ornek.com/piyodo", "events": ["order.paid", "stock.updated"]}'
json
{
  "data": {
    "id": "01J...",
    "url": "https://ornek.com/piyodo",
    "events": ["order.paid", "stock.updated"],
    "active": true,
    "secret": "whsec_..."
  }
}

secret yalnız bu yanıtta döner, sakla. events içinde * tüm olayları abone eder.

Gönderim

Her olayda adresine POST gelir:

json
{
  "event": "order.paid",
  "store_id": "01J...",
  "created_at": "2026-11-05T10:00:00+00:00",
  "data": {}
}
Başlık Değer
Content-Type application/json
X-Piyodo-Event Olay adı
X-Piyodo-Signature sha256=<HMAC-SHA256(imza anahtarı, ham gövde)>
User-Agent Piyodo-Webhook/1.0

İmza doğrulama

Gelen isteğin Piyodo'dan geldiğini imzayla doğrula. HMAC'i ayrıştırılmamış ham gövde üzerinden hesapla: JSON'u çözüp yeniden üretirsen imza tutmaz. Karşılaştırmayı sabit süreli yap.

PHP:

php
$body = file_get_contents('php://input');
$expected = 'sha256='.hash_hmac('sha256', $body, getenv('PIYODO_WEBHOOK_SECRET'));

if (! hash_equals($expected, $_SERVER['HTTP_X_PIYODO_SIGNATURE'] ?? '')) {
    http_response_code(401);
    exit;
}

$event = json_decode($body, true);
http_response_code(200);

Node.js (Express):

js
import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post('/piyodo', express.raw({ type: 'application/json' }), (req, res) => {
    const expected = Buffer.from('sha256=' + crypto.createHmac('sha256', process.env.PIYODO_WEBHOOK_SECRET).update(req.body).digest('hex'));
    const received = Buffer.from(req.get('X-Piyodo-Signature') ?? '');

    if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
        return res.sendStatus(401);
    }

    const event = JSON.parse(req.body);
    res.sendStatus(200);
});

Python (Flask):

python
import hashlib, hmac, os
from flask import Flask, abort, request

app = Flask(__name__)

@app.post('/piyodo')
def piyodo():
    expected = 'sha256=' + hmac.new(os.environ['PIYODO_WEBHOOK_SECRET'].encode(), request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get('X-Piyodo-Signature', '')):
        abort(401)
    event = request.get_json()
    return '', 200

Yeniden deneme

  • Alıcı 10 saniye içinde 2xx dönmezse gönderim başarısız sayılır.
  • Başarısız gönderim 30 saniye ve 5 dakika sonra yeniden denenir, toplam 3 deneme.
  • Yönlendirme izlenmez: 301 ya da 302 de başarısızdır.
  • 3 deneme de başarısızsa hata sayacı bir artar, son hata panelde görünür. Başarılı gönderim sayacı sıfırlar.
  • Üst üste 20 olay başarısız olursa abonelik kapanır. Panelden yeniden açınca sayaç sıfırlanır.

Yanıtı kısa tut, uzun işi kuyruğa at. Aynı olay birden çok kez gelebilir: yanıtın yolda kaybolması yeniden deneme doğurur. Yazılımın aynı olayı iki kez işlemeyecek biçimde kurulmalıdır.

Olaylar

Olay Ne zaman data
order.created Sipariş oluşturuldu Sipariş
order.paid Sipariş ödendi Sipariş
order.confirmed Kapıda ödeme onaylandı Sipariş
order.shipped Sipariş kargolandı Sipariş
order.delivered Sipariş teslim edildi Sipariş
return.requested İade talebi açıldı id, order_id, order_number, reason, note, quantities
booking.created Randevu alındı id, service, status, starts_at, ends_at, customer, order_id
booking.cancelled Randevu iptal edildi Aynı alanlar
order.cancelled Sipariş iptal edildi Sipariş
order.refunded Sipariş iade edildi Sipariş ve refund_amount
product.created Ürün eklendi Ürün
product.updated Ürün güncellendi Ürün
product.deleted Ürün silindi id, slug
stock.updated Stok değişti product_id, variant_id, sku, stock
customer.created Müşteri eklendi Müşteri
ping Paneldeki Dene düğmesi message

Ürün ve müşteri gövdesi de API yanıtıyla aynıdır.

Sipariş gövdesi

Sipariş olaylarının data alanı API yanıtıyla aynıdır: tutarlar "899.90" biçiminde ondalık metindir, dövizli siparişte charge alanı gelir.

order.refunded ayrıca bu iadenin tutarını mağaza para biriminde refund_amount içinde taşır. Toplam iade refunded_total alanındadır.

json
{
  "event": "order.refunded",
  "store_id": "01J...",
  "created_at": "2026-11-05T10:00:00+00:00",
  "data": {
    "id": "01J...",
    "number": 1042,
    "status": "paid",
    "total": "1000.00",
    "refunded_total": "250.00",
    "refund_amount": "250.00"
  }
}

Örnek kısaltılmıştır, data içinde siparişin tüm alanları bulunur.