Ana içeriğe geç

Webhook

Webhook, kayıtlarınızdan birinde bir şey değiştiğinde gateway sunucusunun sizin sunucunuza gönderdiği imzalı bir POST isteğidir ve değişiklikten kısa süre içinde gelir. Müşteri sekmeyi kapatıp dönüş POST'u hiç gelmese de webhook gelir.

Webhook nihai sonuç değildir

Gövde yalnızca değişen kaydın token'ını taşır; durum, tutar ya da müşteri taşımaz. Bildirimi aldığınızda token ile ilgili retrieve-* ucunu çağırın ve kararı o yanıta göre verin. Yanıttaki reference, amount, currency ve durum alanlarını kendi kaydınızla karşılaştırın.

Adres tanımlama​

API isteklerinde webhook adresi gönderilmez. Adresler panelde Ödeme Ayarları → Webhook sayfasında tanımlanır. Her webhook iki bilgiden oluşur:

AlanAçıklama
URLBildirimin gönderileceği adres. https ile başlayan, herkese açık bir adres olmalıdır. Bir adres yalnızca bir kez eklenir.
OlaylarAşağıdaki tablolardan bu adrese gönderilecek olanlar; en az biri seçilir. Tüm olaylar seçilirse her olay aynı adrese gelir.

Aynı olay birden fazla adreste seçilebilir; bildirim her adrese ayrı ayrı gönderilir. Bir webhook panelden kapatılabilir; kapalıyken hiçbir olayı için bildirim gönderilmez. Kapatılmadan önce sıraya girmiş bildirimler de gitmez; silinen adres için de aynısı geçerlidir. Hiçbir adreste seçilmemiş olay için bildirim gönderilmez. Olay listesinde yalnızca çalışma alanınızda açık olan modüllerin olayları yer alır.

Olaylar​

Sipariş​

OlayNe zamanDoğrulama
order.paidSiparişin ödemesi başarılı olduğunda.retrieve-orders: order.status paid.
order.payment_refundedSiparişin ödemesinden tamamen ya da kısmen iade yapıldığında.retrieve-orders: order.transaction.payment_status refunded ya da partially_refunded.
order.payment_cancelledSiparişin ödemesi iptal edildiğinde.retrieve-orders: order.transaction.payment_status cancelled.

Ödeme linki​

OlayNe zamanDoğrulama
payment_link.paidLinkten bir ödeme başarıyla alındığında.retrieve-link-payments (link_payment.token ile): status paid, payment_link.token linkin token'ı, transaction.token bildirimdeki ödeme.
payment_link.payment_refundedLinkten alınan bir ödemeden tamamen ya da kısmen iade yapıldığında.retrieve-link-payments (link_payment.token ile) ya da retrieve-payments (transaction.token ile): transaction.payment_status refunded ya da partially_refunded.
payment_link.payment_cancelledLinkten alınan bir ödeme iptal edildiğinde.retrieve-link-payments (link_payment.token ile) ya da retrieve-payments (transaction.token ile): transaction.payment_status cancelled.

Abonelik​

OlayNe zamanDoğrulama
subscription.activeAboneliğin ilk ödemesi ve sonraki her başarılı yenileme ödemesi alındığında.retrieve-subscriptions: subscription.status active.
subscription.past_dueYenileme ödemesi kayıtlı karttan çekilemediğinde.retrieve-subscriptions: subscription.status past_due.
subscription.cancelledAbonelik iptal edildiğinde. Ödenmiş dönem sürüyorsa abonelik dönem sonuna kadar devam eder.retrieve-subscriptions: subscription.cancelled_at.
subscription.endedİptal edilmiş abonelik durduğunda: ödenmiş dönem yoksa iptalle birlikte, varsa dönem bitince.retrieve-subscriptions: subscription.status cancelled.
subscription.completedrenewal_limit kadar ödeme alınıp son dönem bittiğinde.retrieve-subscriptions: subscription.status completed.
subscription.payment_refundedAboneliğin bir ödemesinden tamamen ya da kısmen iade yapıldığında.retrieve-payments (transaction.token ile): transaction.payment_status, transaction.subscription.token.
subscription.payment_cancelledAboneliğin bir ödemesi iptal edildiğinde.retrieve-payments: transaction.payment_status cancelled.

API ödemesi​

OlayNe zamanDoğrulama
transaction.successfulsecure-payment ya da regular-payment ile başlatılan ödeme başarılı olduğunda.retrieve-payments: transaction.status successful.
transaction.failedAPI ödemesi reddedildiğinde ya da hatayla sonuçlandığında.retrieve-payments: transaction.status failed.
transaction.expiredsecure-payment ile başlatılan ödemenin redirect_url adresi 15 dakika içinde açılmadığında.retrieve-payments: transaction.status expired.
transaction.payment_refundedAPI ödemesinden tamamen ya da kısmen iade yapıldığında.retrieve-payments: transaction.payment_status.
transaction.payment_cancelledAPI ödemesi iptal edildiğinde.retrieve-payments: transaction.payment_status cancelled.

Sipariş, ödeme linki ya da abonelikte alınan ödemeler için transaction.* olayları gönderilmez; o kaydın kendi olayı gönderilir. Sağlayıcısı yanıt vermeyen (timeout) ödeme için bildirim gönderilmez. İade ve iptal olayları yalnızca iade ya da iptal başarılı olduğunda gönderilir.

İstek​

POST /odemehub/webhook HTTP/1.1
Host: magazam.com
Content-Type: application/json
X-Timestamp: 1759396530
X-Signature: 9a3f...e1

{"id":"a41d7e90-3c2f-4f8a-8b6e-9d0c1a2b3e55","event":"order.payment_refunded","created_at":"2026-10-02T09:15:30.000000Z","order":{"token":"3b7e1f20-5c4a-4d8e-9f1b-7a6c5d4e3f21"},"transaction":{"token":"0b8f6c2d-3e41-4a7b-9c5d-1e2f3a4b5c6d"}}
BaşlıkDeğer
Content-Typeapplication/json
X-Timestampİmzanın atıldığı an, Unix saniye.
X-Signatureİmza; bkz. İmza doğrulama.

Gövde​

{
"id": "a41d7e90-3c2f-4f8a-8b6e-9d0c1a2b3e55",
"event": "order.payment_refunded",
"created_at": "2026-10-02T09:15:30.000000Z",
"order": { "token": "3b7e1f20-5c4a-4d8e-9f1b-7a6c5d4e3f21" },
"transaction": { "token": "0b8f6c2d-3e41-4a7b-9c5d-1e2f3a4b5c6d" }
}

Ödeme linki olayında gövde linkin ve link ödemesinin token'ını birlikte taşır (payment_link.paid):

{
"id": "c7e2a9b4-1f3d-4e6a-8b5c-2d4f6a8b0c1e",
"event": "payment_link.paid",
"created_at": "2026-10-02T09:15:30.000000Z",
"payment_link": { "token": "5f1a3c7e-9b2d-4e8f-a6c4-1d3e5f7a9b0c" },
"link_payment": { "token": "e8b4d2f0-6a1c-4f3e-9d7b-5c3a1e9f7d2b" },
"transaction": { "token": "0b8f6c2d-3e41-4a7b-9c5d-1e2f3a4b5c6d" }
}
AlanTipAçıklama
idstringBildirimin kimliği (UUID). Aynı bildirim yeniden gönderildiğinde değişmez; tekrar gelen bildirimi ayıklamak için kullanın.
eventstringOlay adı.
created_atstringBildirimin oluşturulduğu an, ISO 8601 UTC.
order / payment_link / subscription / transactionobjectOlay adının ilk kısmındaki kayıt: { "token": "…" }.
link_paymentobjectYalnızca payment_link.* olaylarında: link ödemesinin token'ı, { "token": "…" }. retrieve-link-payments ile sorgulanır.
transactionobjectSipariş, ödeme linki ve abonelikte para hareketi olan olaylarda (*.paid, subscription.active, *.payment_refunded, *.payment_cancelled) ödemenin token'ı: { "token": "…" }.

Gövde yalnızca token taşır; tutar, durum ya da discount taşımaz. Kayıtları kendi sisteminizde create-* yanıtında aldığınız token ile eşleştirin; reference tekil değildir (ayrıntı).

Abonelik ve ödeme linki olaylarında transaction.token ile retrieve-payments çağırdığınızda yanıttaki transaction.subscription.token ya da transaction.payment_link.token ve transaction.link_payment.token, ödemenin bildirimdeki kayda ait olduğunu gösterir. Ödeme linki olaylarında link_payment.token ile retrieve-link-payments çağırarak link ödemesinin kalemlerini, tutarını ve durumunu da alabilirsiniz.

İmza doğrulama​

İmza, API istek ve yanıtlarıyla aynı yöntemle alınır:

HMAC-SHA256(api_secret, "{X-Timestamp}\nPOST\n{path}\n{body}")

path webhook adresinizin yoludur (baştaki / dahil, sorgu dizesi hariç; yol yoksa /). body gövdenin ham hâlidir. Zaman damgası 5 dakikadan eski olan bildirimi kabul etmeyin. Gövdeyi ayrıştırıp yeniden yazan bir katman (ör. Express'te express.json()) imzayı bozar; gövdeyi ham okuyun.

not

Örneklerdeki $client / client nesnesinin kurulumu: İstemciyi Kurmak.

use Gurmehub\Odemehub\Exception\SignatureException;
use Gurmehub\Odemehub\Request\{RetrieveLinkPayments, RetrieveOrders, RetrievePayments, RetrieveSubscriptions};

try {
$webhook = $client->webhook(
$_SERVER['REQUEST_METHOD'],
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH),
file_get_contents('php://input'),
$_SERVER['HTTP_X_TIMESTAMP'] ?? null,
$_SERVER['HTTP_X_SIGNATURE'] ?? null,
);
} catch (SignatureException $exception) {
http_response_code(401);
exit;
}

if ($webhook->orderToken !== null) {
$order = $client->retrieveOrders(RetrieveOrders::byToken($webhook->orderToken))->orders[0] ?? null;
} elseif ($webhook->linkPaymentToken !== null) { // payment_link.*
$linkPayment = $client->retrieveLinkPayments(RetrieveLinkPayments::byToken($webhook->linkPaymentToken))->linkPayments[0] ?? null;
} elseif ($webhook->subscriptionToken !== null) {
$subscription = $client->retrieveSubscriptions(RetrieveSubscriptions::byToken($webhook->subscriptionToken))->subscriptions[0] ?? null;
} elseif ($webhook->transactionToken !== null) {
$transaction = $client->retrievePayments(RetrievePayments::byToken($webhook->transactionToken))->payments[0] ?? null;
}

http_response_code(204);

Yanıt ve yeniden deneme​

KuralDeğer
İlk gönderimOlaydan 30 saniye sonra. Panelden elle yeniden gönderilen bildirim beklemeden gider.
Beklenen yanıtHerhangi bir 2xx. Yanıt gövdesi kullanılmaz.
Zaman aşımı15 saniye.
Yönlendirmeİzlenmez; 3xx başarısız sayılır.
Başarısız sayılan2xx dışı yanıt, bağlantı hatası ya da zaman aşımı.
Yeniden denemeToplam 5 deneme; denemeler arası 60 sn, 5 dk, 15 dk, 30 dk.

Teslim edilemeyen bildirimler panelde ilgili kaydın sayfasında HTTP kodu ve yanıtıyla listelenir; denemeleri biten bildirim oradan yeniden gönderilebilir. Yeniden gönderilen bildirim aynı id ve gövdeyle gelir. Elle yeniden gönderim, o bildirimin kaydındaki adrese gider; adres sonradan değiştirilmiş, kapatılmış ya da silinmiş olsa da.

Tekrar ve sıra​

  • Aynı bildirim birden fazla kez gelebilir. id alanıyla ayıklayın; işleyiciniz aynı bildirimi ikinci kez işlediğinde sonucu değiştirmemelidir.
  • Bildirimlerin sırası garanti edilmez. Karar her zaman retrieve-* yanıtındaki güncel duruma göre verildiğinde sıra önemli değildir.
  • Bildirim, müşterinin tarayıcısının dönüş POST'undan önce ya da sonra gelebilir; ikisi birbirinden bağımsızdır.