Canlı Altın Fiyatlarıyla Kuyum Fiyat Hesaplayıcısı Geliştirin
TypeScript ve Python ile gram altın fiyatı, ayar, işçilik, KDV ve kotaya uygun önbellekleme içeren sunucu tarafı bir kuyum fiyat hesaplayıcısı geliştirin.
Hesaplayıcı ne yapar
Kuyum ürünleri genellikle dört girdiden fiyatlanır: parçanın ağırlığı, altının saflığı, güncel altın fiyatı ve kuyumcunun işçiliği; bunlara bir de vergi eklenir. Bu hesabı her ürün sayfası veya fiyat teklifi talebi için yapan bir hesaplayıcı, mağazanın para birimi cinsinden gram altın fiyatına ihtiyaç duyar. Üstelik bu fiyatı hızlı, API kotasını aşmadan ve API anahtarını tarayıcıya açmadan alması gerekir.
Bu eğitimde TypeScript (Node.js) ve Python ile sunucu tarafında çalışan küçük bir servis geliştireceğiz. Tarayıcı veya mağazanızın backend'i, kendi endpoint'inize bir ağırlık ve bir ayar gönderir. Sunucunuz bunları MetalAPI'den alınıp önbelleğe alınmış altın fiyatıyla birleştirir ve fiyatın tam dökümünü döndürür. Formül şöyle:
metal değeri = ağırlık (g) × gram altın fiyatı (24K) × saflık
işçilik = gram başına, metal değerinin yüzdesi ya da sabit ücret
net fiyat = metal değeri + işçilik
KDV = net fiyat × KDV oranı
toplam = net fiyat + KDVSpot altın, toptan piyasada kullanılan bir referans fiyattır. Perakende fiyatlar ayrıca tasarımı, taşları, fireyi ve kâr marjını da yansıtır; geri alım fiyatları ise genellikle spot fiyatın altındadır. Bu hesaplayıcıyı fiyatlandırmanızın metale dayalı kısmı olarak görün ve kendi iş kurallarınızı bunun üzerine ekleyin.
Kendi para biriminizde gram altın
/latest endpoint'i fiyatları istediğiniz baz para biriminde ve metaller için istediğiniz ağırlık biriminde döndürür. Tek bir istekle bir gram saf altının euro cinsinden fiyatını alırsınız:
curl "https://metalapi.com/api/v1/latest?base=EUR¤cies=XAU&unit=gram" \
-H "X-API-Key: YOUR_API_KEY"{
"success": true,
"timestamp": 1792834892,
"date": "2026-10-24",
"base": "EUR",
"unit": "gram",
"rates": {
"XAU": 0.0090909091,
"EURXAU": 110
},
"rate_limit": { "limit": 10000, "remaining": 9874, "...": "..." }
}rates.EURXAU, bir birim XAU'nun (burada bir gramın) baz para birimi cinsinden fiyatıdır. Hesaplayıcının ihtiyaç duyduğu sayı budur. rates.XAU ise bunun tersidir, yani euro başına gram altın miktarı. Birim varsayılan troy ons dışında olduğunda yanıt unit alanını içerir; timestamp ise fiyat verisinin zamanıdır. Bu zamanı her fiyat teklifinin yanında gösterin.
Baz para birimi ve birim, Free dahil her planda çalışır. Gümüş veya platin ürünler de satıyorsanız aynı isteğe XAG, XPT ve XPD sembollerini ekleyebilirsiniz. Ücretli planlar ayrıca XAU22K gibi ayar fiyatlarını doğrudan ya da carat=all ile tüm ayarları tek seferde döndüren carat endpoint'ini kullanabilir. Bu eğitimde saflık hesabını kendimiz yapıyoruz; böylece kod her planda çalışır ve bir sonraki konu olan milyem damgası değerlerini kullanabilir.
Saflık, işçilik ve KDV
Ayar, altın içeriğini 24'te bir cinsinden ifade eder; bu nedenle saflık katsayısı karat / 24 olur ve /carat endpoint'i de bu kuralı kullanır. Ancak birçok piyasada altın, binde kaç parça saf altın içerdiğini gösteren milyem değeriyle damgalanır ve bazı ayarlarda iki değer arasında küçük farklar vardır:
| Ayar | ayar / 24 | Yaygın milyem damgası |
|---|---|---|
| 24K | 1,0000 | 999 |
| 22K | 0,9167 | 916 |
| 21K | 0,8750 | 875 |
| 18K | 0,7500 | 750 |
| 14K | 0,5833 | 585 |
| 9K | 0,3750 | 375 |
Temsili olarak gramı 110 € olan altınla 5,2 g ağırlığındaki 14 ayar bir yüzük için 14/24 ile metal değeri 333,67 €, 0.585 ile ise 334,62 € çıkar. İkisi de yanlış değildir. Damgalarınızda ve faturalarınızda hangi kural kullanılıyorsa onu kullanın; aşağıdaki kodun ayar yerine saflık katsayısı almasının nedeni de budur. Konunun arka planı ayar fiyatları rehberinde daha ayrıntılı anlatılıyor.
İşçilik ücreti genellikle üç biçimden birinde uygulanır ve TypeScript sürümü üçünü de destekler:
- Gram başına: parçanın her gramı için sabit bir tutar, örneğin gram başına 12 €.
- Yüzde: metal değerinin belirli bir oranı, örneğin %8. Altın fiyatıyla birlikte artar ve azalır.
- Sabit: parça başına sabit bir ücret; küçük ürünlerde ve özel tasarım işlerde yaygındır.
KDV veya satış vergisi en son eklenir. Oran ve verginin neye uygulanacağı ülkeye göre değişir: bazı ülkeler fiyatın tamamını vergilendirir, bazıları yatırımlık altını kuyum ürünlerinden farklı değerlendirir, bazıları ise yalnızca işçiliği vergilendirir. Oranı ve vergiye tabi tutarı yapılandırmada tutun, bunları mali müşavirinizle teyit edin ve her satırı kuruşa yuvarlayın; böylece faturadaki satırların toplamı fatura toplamıyla tutar.
Kotanızın içinde kalmak için önbellekleme
Her plan fiyatları sabit bir aralıkla günceller ve güncellemeler, 00:00 UTC'den itibaren sayılan bu aralığın katlarına denk gelir: Standard planda :00, :10, :20 gibi dakikalarda, Free planda ise günde bir kez UTC gece yarısında. Bu sınırlardan ikisi arasındaki her istek aynı fiyatları döndürür; bu nedenle ideal önbellek her sınırda bir kez yenilenir. Günün her saatinde her sınırda yenilemenin 31 günlük bir aydaki maliyeti şöyledir:
| Plan (aylık kota) | Güncelleme aralığı | Her sınırda yenilemede istek sayısı | Kota içinde mi? |
|---|---|---|---|
| Free (100) | Günlük | 31 | Evet |
| Lite (1.000) | 30 dk | 1.488 | Hayır: bunun yerine saatte bir yenileyin (744) |
| Standard (10.000) | 10 dk | 4.464 | Evet |
| Advanced (50.000) | 1 dk | 44.640 | Evet, ancak diğer çağrılara daha az pay kalır |
İki kural daha önbelleği sağlamlaştırır. Single flight kullanın: yük altındayken önbelleğin süresi dolduğunda ilk istek yeni fiyatı alır, eşzamanlı istekler ise her biri ayrı ayrı API'yi çağırmak yerine bu sonucu bekler. Ve hata durumunda eski fiyatı sunun (serve stale on error): API'ye ulaşılamıyorsa her ödeme işlemini başarısız kılmak yerine son geçerli fiyatla birkaç saat boyunca teklif vermeye devam edin ve dakikada bir yeniden deneyin. Sunucu hatasıyla başarısız olan istekler ücretlendirilmez, ancak bir kesinti sırasında art arda istek göndermenin yine de bir anlamı yoktur.
Aşağıdaki önbellek işlem belleğinde (process memory) tutulur; bu, tek bir sunucu için idealdir. Serverless platformlarda veya birden fazla instance ile çalışırken her instance kendi kopyasını tutar. Fiyatı Redis gibi paylaşılan bir depoya koyun ya da framework'ünüzün veri önbelleğini aynı sona erme süresiyle kullanın.
TypeScript uygulaması
Aşağıdaki modül Node.js 18 veya daha yeni sürümlerde çalışır ve hiçbir bağımlılığı yoktur. Gram başına euro fiyatını alır, bir sonraki plan sınırına kadar önbellekte tutar ve bir ağırlığı, bir saflık katsayısını ve bir işçilik ücretini fiyatlandırılmış bir dökümle sonuçlandırır:
// gold-quote.ts — Node 18+. API anahtarı sunucuda kalır.
const API_KEY = process.env.METALAPI_KEY!;
const CURRENCY = "EUR";
const PLAN_INTERVAL_S = 600; // Standard plan: fiyatlar 10 dakikada bir güncellenir
const MIN_TTL_S = 0; // Lite plan: ayda 1.000 isteğin altında kalmak için 3600 yapın
interface GoldPrice {
perGram: number; // saf (24K) altın, gram başına CURRENCY
timestamp: number; // fiyat verisinin zamanı (Unix saniyesi)
fetchedAt: number;
expiresAt: number;
}
let cached: GoldPrice | null = null;
let inflight: Promise<GoldPrice> | null = null;
// Fiyatlar yalnızca plan aralığının katlarında değişir (00:00 UTC'den itibaren sayılır).
function nextBoundary(ms: number): number {
const step = PLAN_INTERVAL_S * 1000;
return Math.floor(ms / step) * step + step;
}
async function fetchGold(): Promise<GoldPrice> {
const url = `https://metalapi.com/api/v1/latest?base=${CURRENCY}¤cies=XAU&unit=gram`;
const res = await fetch(url, { headers: { "X-API-Key": API_KEY }, signal: AbortSignal.timeout(10_000) });
const body = await res.json();
if (!body.success) throw new Error(`MetalAPI ${body.error.code}: ${body.error.info}`);
const now = Date.now();
return {
perGram: body.rates[`${CURRENCY}XAU`],
timestamp: body.timestamp,
fetchedAt: now,
expiresAt: nextBoundary(now + MIN_TTL_S * 1000) + 5_000, // birkaç saniyelik pay
};
}
export function goldPerGram(): Promise<GoldPrice> {
if (cached && Date.now() < cached.expiresAt) return Promise.resolve(cached);
// Single flight: eşzamanlı istekler tek bir API çağrısını paylaşır.
inflight ??= fetchGold()
.then((fresh) => (cached = fresh))
.catch((err) => {
// Son geçerli fiyatı en fazla 6 saat kullanmaya devam et; bir dakika sonra yeniden dene.
if (cached && Date.now() - cached.fetchedAt < 6 * 3600_000) {
cached.expiresAt = Date.now() + 60_000;
return cached;
}
throw err;
})
.finally(() => (inflight = null));
return inflight;
}
export type MakingCharge =
| { type: "per_gram"; amount: number }
| { type: "percent"; rate: number } // 0.08 = metal değerinin %8'i
| { type: "flat"; amount: number };
const money = (n: number) => Math.round(n * 100 + Number.EPSILON) / 100;
export async function quote(grams: number, purity: number, making: MakingCharge, vatRate: number) {
const gold = await goldPerGram();
const metal = money(grams * gold.perGram * purity);
const labour = money(
making.type === "per_gram" ? grams * making.amount
: making.type === "percent" ? metal * making.rate
: making.amount,
);
const net = money(metal + labour);
const vat = money(net * vatRate);
return {
currency: CURRENCY,
grams,
purity,
gold_per_gram_24k: gold.perGram,
price_time: new Date(gold.timestamp * 1000).toISOString(),
metal,
making: labour,
net,
vat,
total: money(net + vat),
};
}Birkaç satır daha yakından bakmayı hak ediyor. nextBoundary(), değeri plan aralığının bir sonraki katına yuvarlar; böylece Standard planda saat 10:03'te alınan bir fiyatın süresi 10:13'te değil, bir sonraki güncellemeden birkaç saniye sonra, 10:10:05'te dolar. Lite planda MIN_TTL_S değeri 3600 yapıldığında bir sonraki yenileme en az bir saat sonraki ilk sınırı bekler; bu da kullanımı günde 24 istekle sınırlar. .catch dalı, eski fiyatı sunma kuralını uygular: son geçerli fiyatı döndürür ve bir sonraki denemeyi bir dakika sonraya planlar. Böylece bir kesinti, her ziyaretçi için bir başarısız istek yerine dakikada en fazla bir başarısız isteğe mal olur.
Modülü küçük bir HTTP endpoint'i üzerinden sunun. Girdileri sıkı biçimde doğrulayın: yalnızca sattığınız saflıkları ve makul bir ağırlık aralığını kabul edin. İşçilik ücreti ve KDV oranı sunucu tarafı ayarlarıdır; bunları asla istemciden kabul etmeyin.
// server.ts — npm install express, ardından: METALAPI_KEY=mk_live_... npx tsx server.ts
import express from "express";
import { quote } from "./gold-quote";
// Ürünlerinizdeki damgaya göre saflık katsayıları (yukarıdaki ayar tablosuna bakın).
const PURITY: Record<string, number> = { "24": 0.999, "22": 0.916, "21": 0.875, "18": 0.75, "14": 0.585, "9": 0.375 };
const app = express();
app.get("/api/jewelry-quote", async (req, res) => {
const grams = Number(req.query.grams);
const purity = PURITY[String(req.query.karat)];
if (!purity || !(grams > 0 && grams <= 2000)) {
res.status(400).json({ error: "Use karat 24, 22, 21, 18, 14 or 9 and grams between 0 and 2000." });
return;
}
try {
// İşçilik ve KDV sunucu tarafı ayarlarıdır, asla istemci girdisi değildir.
res.json(await quote(grams, purity, { type: "per_gram", amount: 12 }, 0.2));
} catch (err) {
console.error(err);
res.status(503).json({ error: "Gold price temporarily unavailable." });
}
});
app.listen(3000, () => console.log("Try http://localhost:3000/api/jewelry-quote?karat=18&grams=5.2"));/api/jewelry-quote?karat=18&grams=5.2 adresine yapılan bir istek, aşağıdakine benzer bir döküm döndürür (temsili altın fiyatıyla):
{
"currency": "EUR",
"grams": 5.2,
"purity": 0.75,
"gold_per_gram_24k": 110,
"price_time": "2026-10-24T09:41:32.000Z",
"metal": 429,
"making": 62.4,
"net": 491.4,
"vat": 98.28,
"total": 589.68
}Python uygulaması
Python sürümü aynı tasarımı izler. Para tutarları için Decimal kullanır, böylece tutarlara ikili kayan nokta hataları karışmaz; ayrıca thread kullanan bir sunucuda eşzamanlı isteklerin tek bir API çağrısını paylaşması için bir kilit (lock) kullanır. Kodu kısa tutmak için yalnızca gram başına işçilik ücretini destekler:
# gold_quote.py — Python 3.9+, pip install requests
import math
import os
import threading
import time
from decimal import ROUND_HALF_UP, Decimal
import requests
API_KEY = os.environ["METALAPI_KEY"]
CURRENCY = "EUR"
PLAN_INTERVAL_S = 600 # Standard plan: fiyatlar 10 dakikada bir güncellenir
MIN_TTL_S = 0 # Lite plan: ayda 1.000 isteğin altında kalmak için 3600 yapın
_lock = threading.Lock()
_cache = {"per_gram": None, "timestamp": 0, "fetched": 0.0, "expires": 0.0}
def _next_boundary(t: float) -> float:
return (math.floor(t / PLAN_INTERVAL_S) + 1) * PLAN_INTERVAL_S
def gold_per_gram() -> tuple[Decimal, int]:
"""Gram başına CURRENCY cinsinden saf (24K) altın ve bu fiyatın Unix zamanı."""
with _lock: # aynı anda tek API çağrısı; bekleyen thread'ler onun sonucunu kullanır
now = time.time()
if _cache["per_gram"] is not None and now < _cache["expires"]:
return _cache["per_gram"], _cache["timestamp"]
try:
r = requests.get(
"https://metalapi.com/api/v1/latest",
params={"base": CURRENCY, "currencies": "XAU", "unit": "gram"},
headers={"X-API-Key": API_KEY},
timeout=10,
)
body = r.json()
if not body.get("success"):
raise RuntimeError(f"MetalAPI {body['error']['code']}: {body['error']['info']}")
except Exception:
if _cache["per_gram"] is not None and now - _cache["fetched"] < 6 * 3600:
_cache["expires"] = now + 60 # son geçerli fiyatı sun, bir dakika sonra yeniden dene
return _cache["per_gram"], _cache["timestamp"]
raise
_cache.update(
per_gram=Decimal(str(body["rates"][f"{CURRENCY}XAU"])),
timestamp=body["timestamp"],
fetched=now,
expires=_next_boundary(now + MIN_TTL_S) + 5,
)
return _cache["per_gram"], _cache["timestamp"]
def money(x: Decimal) -> Decimal:
return x.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
def quote(grams: Decimal, purity: Decimal, making_per_gram: Decimal, vat_rate: Decimal) -> dict:
per_gram, ts = gold_per_gram()
metal = money(grams * per_gram * purity)
making = money(grams * making_per_gram)
net = metal + making
vat = money(net * vat_rate)
return {
"currency": CURRENCY,
"gold_per_gram_24k": str(per_gram),
"price_time": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(ts)),
"metal": str(metal),
"making": str(making),
"net": str(net),
"vat": str(vat),
"total": str(net + vat),
}Bunu her web framework'ü sunabilir. FastAPI'de düz def endpoint'leri bir thread havuzunda çalışır; kilit de tam olarak bu durum için var:
# app.py — pip install fastapi uvicorn requests, ardından: METALAPI_KEY=mk_live_... uvicorn app:app
from decimal import Decimal
from fastapi import FastAPI, HTTPException, Query
from gold_quote import quote
# Ürünlerinizdeki damgaya göre saflık katsayıları.
PURITY = {24: Decimal("0.999"), 22: Decimal("0.916"), 21: Decimal("0.875"),
18: Decimal("0.750"), 14: Decimal("0.585"), 9: Decimal("0.375")}
app = FastAPI()
@app.get("/api/jewelry-quote")
def jewelry_quote(karat: int, grams: Decimal = Query(gt=0, le=2000)):
if karat not in PURITY:
raise HTTPException(400, "Use karat 24, 22, 21, 18, 14 or 9.")
try:
return quote(grams, PURITY[karat], making_per_gram=Decimal("12.00"), vat_rate=Decimal("0.20"))
except Exception:
raise HTTPException(503, "Gold price temporarily unavailable.")Python sürümü tutarları string olarak, TypeScript sürümü ise sayı olarak döndürür. Bir fiyat teklifi bir sipariş sistemine aktarılacaksa tutarları kayan noktalı sayı olarak değil, ondalık string veya tam sayı kuruş olarak saklayın.
Örnek bir hesaplama
Aşağıda 18 ayar yüzüğün adım adım fiyatlandırmasını görüyorsunuz. Temsili altın fiyatı gram başına 110,00 €, işçilik gram başına 12 € ve KDV %20'dir:
| Adım | Hesaplama | Tutar |
|---|---|---|
| 24 ayar altın, gram başına | rates.EURXAU | 110,00 € |
| Saflık | 18 ayar, 750 damgası | 0,75 |
| Metal değeri | 5,2 g × 110,00 € × 0,75 | 429,00 € |
| İşçilik | 5,2 g × 12,00 € | 62,40 € |
| Net fiyat | 429,00 € + 62,40 € | 491,40 € |
| KDV | 491,40 € × %20 | 98,28 € |
| Toplam | 589,68 € |
Şimdi aynı altın fiyatıyla, %8 işçilik ücretine sahip 10 g ağırlığındaki 22 ayar bir zinciri ele alalım. 22/24 saflıkla metal değeri 1.008,33 €, işçilik bunun %8'i (80,67 €), net fiyat 1.089,00 € ve KDV dahil toplam 1.306,80 € olur. 916 damga katsayısıyla ise metal değeri 1.007,60 € olurdu.
Altın fiyatını yalnızca metal değeri izlediği için toplam fiyat, altının kendisinden daha az değişir. Altın %1 artarak gram başına 111,10 €'ya çıkarsa 18 ayar yüzüğün metal değeri 433,29 €, toplamı ise 594,83 € olur; bu 5,15 €, yani %0,87'lik bir artıştır. Yüzde olarak hesaplanan bir işçilik ücreti, toplamın altın fiyatını daha yakından izlemesini sağlar.
Canlı ortam kontrol listesi
- API anahtarını sunucuda bir ortam değişkeninde tutun. Hesaplayıcı endpoint'i anahtarı değil, yalnızca fiyatları döndürür.
- Müşterilerin ve çalışanların altın fiyatının ne kadar güncel olduğunu görebilmesi için her fiyat teklifinde
price_timedeğerini gösterin. - Sipariş verildiği anda fiyatı sabitleyin: daha sonra yeniden hesaplamak yerine altın fiyatını, zaman damgasını, saflığı ve her satır tutarını siparişle birlikte saklayın.
- Altın piyasasının kapalı olduğu hafta sonlarında fiyatların sabit kalmasını bekleyin. Bu, önbelleğin eskidiği anlamına gelmez.
- Kotanızdan düşülmeyen usage endpoint'i ile kullanımınızı takip edin ve ay bitmeden kendinizi uyarın.
105hatasını (aylık kota tükendi) önbellekteki fiyatı sunarak ve ekibinizi uyararak ele alın. Kota her ayın 1'inde 00:00 UTC'de sıfırlanır; plan yükseltmeleri ise hemen geçerli olur.- Büyük fiyat hareketlerine tepki vermek, örneğin kataloğunuzu yeniden fiyatlandırmak için sorgulama sıklığını artırmak yerine webhook'lu fiyat alarmlarını kullanın.
Planları ve kotaları fiyatlandırma sayfasında karşılaştırın ya da bir anahtar alıp hesaplayıcıyı gerçek fiyatlarla denemek için ücretsiz bir hesap oluşturun.
Kendi verilerinizle deneyin
Ücretsiz bir hesap oluşturun ve ilk isteğinizi iki dakikadan kısa sürede gönderin. Ayda 100 istek, kredi kartı gerekmez.
Okumaya devam edin
Altın Fiyatı API'si: Geliştiriciler İçin Eksiksiz Rehber
Altın fiyatı API'si nasıl kullanılır: anahtar alın, curl, JavaScript ve Python ile çağırın, kurları doğru okuyun; geçmiş veri, hata, kota ve önbelleği yönetin.
Web Sitenize Canlı Altın Fiyatı Widget'ı Nasıl Eklenir
WordPress, Shopify veya HTML sitenize canlı altın fiyatı widget'ı ekleyin: MetalAPI panelinde oluşturun, sembol, düzen ve temayı seçin, iki satırı yapıştırın.
Altın Ayar Fiyatları: 24, 22 ve 18 Ayar Nedir, Nasıl Hesaplanır?
24, 22 ve 18 ayar ne demek, 916 ve 750 gibi milyem damgaları ne anlama gelir, ayar altının gram fiyatı nasıl hesaplanır ve altın fiyatı API'sinden nasıl alınır?