Webhook'lar ve Fiyat Alarmları
Bir fiyat belirlediğiniz eşiği geçtiğinde imzalı HTTP geri çağrıları alın ve bunları HMAC-SHA256 ile doğrulayın; Node.js ve PHP örnekleriyle adım adım.
Alarmlar ve webhook'lar nasıl çalışır
MetalAPI, bir fiyat alarmı tetiklendiğinde webhook gönderir. Bir alarm, seçtiğiniz bir para birimi cinsinden tek bir sembolü izler. Fiyat bir eşiğin üzerine çıktığında veya altına düştüğünde ya da bir önceki kapanıştan bu yana belirli bir yüzde kadar yükseldiğinde veya düştüğünde tetiklenir.
Alarmlar eşik geçildiği anda tetiklenir: koşul gerçekleştiğinde bir kez bilgilendirilirsiniz ve koşul yeniden geçersiz hale geldikten sonra alarm tekrar kurulur. Bir bekleme süresi (varsayılan 60 dakika; 5 dakika ile 7 gün arasında ayarlanabilir), fiyat eşiğin çevresinde dalgalandığında art arda bildirim gelmesini önler.
Alarmlar sizi Lite ve üzeri planlarda e-posta ile, Advanced ve üzeri planlarda ise webhook ile (sunucunuza bir HTTPS POST isteği) bilgilendirir.
Webhook kurulumu
- Paneldeki Alerts bölümünü açın ve bir alarm oluşturun.
- Sembolü, para birimini, koşulu ve eşiği seçin.
- Gönderim yöntemi olarak webhook'u seçin ve endpoint URL'nizi girin.
- Webhook imzalama gizli anahtarınızı (
whsec_ile başlar) panelden kopyalayıp sunucunuzun yapılandırmasına ekleyin.
Webhook URL'leri herkese açık bir sunucuda https:// kullanmalıdır. Kimlik bilgisi içeren veya özel ya da dahili IP adreslerine çözümlenen URL'ler reddedilir ve yönlendirmeler takip edilmez.
Payload
Her gönderim, aşağıdaki header'lara ve gövdeye sahip bir JSON POST isteğidir:
POST /webhooks/metalapi HTTP/1.1
Content-Type: application/json
User-Agent: MetalAPI-Webhooks/1.0
X-MetalAPI-Timestamp: 1792765800
X-MetalAPI-Signature: t=1792765800,v1=3b9f0c4e…a71d
{
"event": "alert.triggered",
"id": 18342,
"created": 1792765800,
"alert": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"symbol": "XAU",
"base": "USD",
"condition": "above",
"threshold": 4000,
"note": "Gold above 4k"
},
"price": 4001.25,
"unit": "troy_oz"
}condition; above, below, change_pct_up veya change_pct_down değerlerinden biridir. price, alarmı tetikleyen fiyattır ve unit başına base cinsinden ifade edilir. id her olay için benzersizdir; yinelenen gönderimleri yok saymak için kullanabilirsiniz.
İmzayı doğrulama
Bir istek üzerine işlem yapmadan önce isteğin gerçekten MetalAPI'den geldiğini her zaman doğrulayın. X-MetalAPI-Signature header'ı t=<unix timestamp>,v1=<signature> biçimindedir. İmza, <timestamp>.<raw request body> dizesinin imzalama gizli anahtarınızla hesaplanan, hex kodlu HMAC-SHA256 değeridir.
- HMAC'i herhangi bir JSON ayrıştırması yapmadan önce, ham gövde üzerinden hesaplayın.
- İmzaları sabit zamanlı (constant-time) bir karşılaştırmayla kıyaslayın.
- Tekrar oynatılan (replay) istekleri engellemek için beş dakikadan eski zaman damgalarını reddedin.
Express kullanan bir Node.js uygulamasında:
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.METALAPI_WEBHOOK_SECRET;
app.post("/webhooks/metalapi", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("X-MetalAPI-Signature") ?? "";
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const body = req.body.toString("utf8");
const expected = crypto.createHmac("sha256", SECRET).update(`${parts.t}.${body}`).digest("hex");
const valid =
typeof parts.v1 === "string" &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
if (!valid || !fresh) return res.status(400).send("invalid signature");
const event = JSON.parse(body);
console.log(event.alert.symbol, event.alert.condition, event.alert.threshold, event.price);
res.sendStatus(200);
});PHP ile doğrulama
Aynı kontrol, düz PHP ile:
<?php
$secret = getenv('METALAPI_WEBHOOK_SECRET');
$payload = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_METALAPI_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $parts);
$timestamp = (int) ($parts['t'] ?? 0);
$expected = hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
if (!hash_equals($expected, $parts['v1'] ?? '') || abs(time() - $timestamp) > 300) {
http_response_code(400);
exit('invalid signature');
}
$event = json_decode($payload, true);
// $event['alert'] ve $event['price'] değerlerini burada işleyin.
http_response_code(200);Yanıt verme ve yeniden denemeler
8 saniye içinde herhangi bir 2xx durum kodu döndürün. Zaman alan işleri yanıt verdikten sonra (örneğin bir kuyrukta) yapın; çünkü zaman aşımları ve 2xx dışındaki yanıtlar başarısız gönderim sayılır.
Başarısız gönderimler giderek uzayan aralıklarla yeniden denenir; alarm tetiklendikten sonraki ilk bir saat içinde toplamda en fazla üç deneme yapılır. Bizim tarafımızda zaman aşımına uğrayan ancak sizin tarafınızda başarıyla işlenen bir gönderimin ardından da yeniden deneme gelebilir; bu nedenle olayın id değerini saklayın ve işleyicinizi idempotent hale getirin.
İlgili rehberler
Geliştirmeye başlamaya hazır mısınız?
API anahtarınızı almak için ücretsiz bir hesap oluşturun veya API referansında tüm endpoint'leri inceleyin.