Sipariş kargo kartı
Takip numarasından olası kargo firması ve takip bağlantısı, resmî tatilleri sayan teslim tahmini, kutu ölçülerinden desi.
- Anahtar al. Ücretsiz kayıt, ayda 1.000 kredi. Anahtarı panelde üretirsin;
ak_live_ile başlar. - Dosyayı al. Aşağıdan kopyala ya da indir:
kargo.mjs. Node 18 ya da üstü yeter, paket yok. - Çalıştır.
KILAVUZ_ANAHTAR=ak_live_… node kargo.mjs. Sayfa localhost:3000’de açılır.
Tek dosya, olduğu gibi çalışır:
// Sipariş kargo kartı: takip numarasından olası kargo firması ve takip bağlantısı,
// resmî tatilleri sayan teslim tahmini, ölçülerden desi.
// Node 18+, paket yok. KILAVUZ_ANAHTAR=ak_live_… node kargo.mjs → http://localhost:3000
// Anahtar yalnız bu sunucuda durur; tarayıcı aşağıdaki izinli uçlara gider, sunucu Kılavuz'a iletir.
import { createServer } from 'node:http';
const API = 'https://api.kilavuzapi.com';
const ANAHTAR = process.env.KILAVUZ_ANAHTAR;
if (!ANAHTAR) throw new Error('KILAVUZ_ANAHTAR tanımlı değil (anahtar: kilavuzapi.com/panel)');
const IZINLI = ['/v1/kargo/takip-tani', '/v1/kargo/teslim-tahmini', '/v1/kargo/desi'];
const PORT = process.env.PORT ?? 3000;
createServer(async (istek, yanit) => {
const { pathname, search } = new URL(istek.url, 'http://yerel');
if (!IZINLI.includes(pathname)) return yanit.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }).end(SAYFA);
let govde = '';
for await (const parca of istek) if ((govde += parca).length > 10_000) return yanit.writeHead(413).end();
try {
const r = await fetch(API + pathname + search, {
method: istek.method,
headers: { authorization: `Bearer ${ANAHTAR}`, 'content-type': 'application/json' },
body: istek.method === 'POST' ? govde : undefined,
});
yanit.writeHead(r.status, { 'content-type': 'application/json; charset=utf-8' }).end(await r.text());
} catch {
yanit.writeHead(502, { 'content-type': 'application/json; charset=utf-8' }).end('{"hata":"Kılavuz API\'sine ulaşılamadı"}');
}
}).listen(PORT, '127.0.0.1', () => console.log(`http://localhost:${PORT}`));
const SAYFA = `<!doctype html>
<html lang="tr">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sipariş kargosu</title>
<style>
body { font: 16px/1.5 system-ui, sans-serif; max-width: 30rem; margin: 40px auto; padding: 0 16px; color: #16181c; }
form { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px 10px; }
label { font-size: 13px; color: #4d535b; }
.genis { grid-column: span 2; }
.tam { grid-column: 1 / -1; }
input { display: block; box-sizing: border-box; width: 100%; margin-top: 2px; padding: 8px 10px; font: inherit; color: #16181c; border: 1px solid #c3c7cd; border-radius: 6px; }
button { grid-column: 1 / -1; padding: 10px 14px; font: inherit; border: 0; border-radius: 6px; background: #16181c; color: #fff; cursor: pointer; }
dl { margin: 24px 0 0; border: 1px solid #dfe2e6; border-radius: 10px; }
dl div { padding: 12px 16px; }
dl div + div { border-top: 1px solid #dfe2e6; }
dt { font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: #6b7280; }
dd { margin: 2px 0 0; font-size: 18px; }
small { display: block; font-size: 12px; color: #6b7280; }
</style>
<h1>Sipariş #1048</h1>
<form id="form">
<label class="tam">Takip no <input name="numara" value="1234 5678 9012"></label>
<label class="genis">Gönderen il <input name="gonderenIl" value="İstanbul"></label>
<label class="genis">Alıcı il <input name="aliciIl" value="Van"></label>
<label>En (cm) <input name="en" value="40" inputmode="decimal"></label>
<label>Boy (cm) <input name="boy" value="30" inputmode="decimal"></label>
<label>Yükseklik <input name="yukseklik" value="20" inputmode="decimal"></label>
<label>Ağırlık (kg) <input name="agirlik" value="3.2" inputmode="decimal"></label>
<button>Hesapla</button>
</form>
<dl id="kart"></dl>
<script>
const form = document.getElementById('form');
const kart = document.getElementById('kart');
const gun = (t) => new Date(t + 'T12:00:00').toLocaleDateString('tr-TR', { day: 'numeric', month: 'long', weekday: 'long' });
const gonder = (yol, govde) => fetch(yol, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(govde),
}).then((r) => r.json()).catch(() => ({ hata: 'yanıt alınamadı' }));
function satir(baslik, metin, not, baglanti) {
const div = document.createElement('div');
const dt = document.createElement('dt');
const dd = document.createElement('dd');
const alt = document.createElement('small');
dt.textContent = baslik;
dd.textContent = metin;
alt.textContent = not || '';
if (baglanti) {
const a = Object.assign(document.createElement('a'), { href: baglanti, textContent: ' Takip et', target: '_blank' });
alt.append(a);
}
div.append(dt, dd, alt);
kart.append(div);
}
form.onsubmit = async (e) => {
e?.preventDefault();
kart.textContent = '';
const sayi = (ad) => Number(form[ad].value.replace(',', '.'));
const bugun = new Date().toLocaleDateString('sv-SE', { timeZone: 'Europe/Istanbul' });
const tani = await gonder('/v1/kargo/takip-tani', { numara: form.numara.value });
const firma = tani.adaylar?.[0];
const [teslim, desi] = await Promise.all([
gonder('/v1/kargo/teslim-tahmini', { gonderimTarihi: bugun, gonderenIl: form.gonderenIl.value, aliciIl: form.aliciIl.value, tasiyici: firma?.kod }),
gonder('/v1/kargo/desi', { en: sayi('en'), boy: sayi('boy'), yukseklik: sayi('yukseklik'), agirlik: sayi('agirlik') }),
]);
satir('Kargo', tani.hata ?? (firma ? firma.ad + ' (olası)' : 'Firma tanınmadı'),
firma && 'Biçime göre tahmin, güven %' + Math.round(firma.guven * 100) + '.', firma?.takipUrl);
satir('Teslim', teslim.hata ?? gun(teslim.tahminiTeslim) + ' tahmini',
!teslim.hata && teslim.isGunu + ' iş günü, en geç ' + gun(teslim.enGec) + '. Resmî tatiller iş günü sayılmaz.');
satir('Desi', desi.hata ?? desi.desi.toLocaleString('tr-TR') + ' desi',
!desi.hata && 'Ücretlendirilen: ' + desi.ucretlendirilenAgirlik.toLocaleString('tr-TR') + (desi.esas === 'desi' ? ' (hacme göre)' : ' (ağırlığa göre)'));
};
form.onsubmit();
</script>
`;
Önce anahtarı ver (export KILAVUZ_ANAHTAR="ak_live_…"), sonra terminalde:
curl -O https://kilavuzapi.com/ornekler/kargo.mjs
node kargo.mjsSayfa http://localhost:3000 adresinde açılır; başka port için başa PORT=8080 ekle.
Kullandığı uçlar
POST /v1/kargo/takip-taniücretsizPOST /v1/kargo/teslim-tahmini1 krediPOST /v1/kargo/desiücretsiz
Anahtar tarayıcıya inmez. Dosya küçük bir sunucu: sayfayı verir, tarayıcının isteğini anahtarı ekleyerek Kılavuz’a iletir. Yalnız IZINLI listesindeki uçlar geçer. Kendi uygulamana taşırken de anahtarı sunucuda tut. Uçların ayrıntısı dokümanda.
Öteki örnekler
- Kendini düzelten adres formuMüşteri adresi tek satırda nasıl yazarsa yazsın; il, ilçe, mahalle, sokak, bina ve daire ayrı alanlara dolar, sicille eşleşmeyen alan işaretlenir./v1/address/resolve
- Şehir kartıBir il yaz: havası, benzin fiyatı, son 24 saatin depremleri ve namaz vakitleri tek kartta, her satırda kaynağı ve saatiyle./v1/hava/durum · /v1/akaryakit/fiyat · /v1/deprem/son · /v1/takvim/namaz
- En yakın hastaneKonumun 10 km çevresindeki hastaneler, uzaklık ve türüyle (kamu, özel, üniversite). Konum tarayıcıdan ya da elle koordinat./v1/saglik/hastane
- Deprem botuSon bir saatte 4 ve üstü deprem olursa Slack’e ya da başka bir webhook’a büyüklük, yer, derinlik ve saatle yazar. Tek istek, AFAD verisi./v1/deprem/son