Skip to Content
BaşlangıçHızlı başlangıç

Hızlı başlangıç

Hedef: uçtan uca gerçek bir test-modu ödemesi almak. Sonunda sunucunuzdan oluşturulmuş bir oturumunuz, alıcının tarayıcısında açılan bir checkout’unuz ve localhost’unuza teslim edilmiş imzalı bir webhook’unuz olacak.

Bir test API anahtar çiftine (pk_test_… + sk_test_…) ve bir webhook imzalama secret’ına (whsec_…) ihtiyacınız var. Bunları satıcı panelinde  Geliştiriciler → API anahtarları ve Geliştiriciler → Webhook’lar altında oluşturun.

1. Tarayıcı SDK’sını yükleyin

npm install @lartech/infraio-checkout-js

2. Bir checkout oturumu oluşturun (sunucu)

Oturumlar sunucunuzdan oluşturulur ve secret anahtarınızla HMAC-SHA256 kullanılarak imzalanır. sk_’yi asla tarayıcıya koymayın.

Kanonik imzalama dizesini oluşturun

METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY

Gövdesi {...} olan ve 1715990400 unix timestamp’inde yapılan bir POST /b2b/v1/checkout-sessions/quick isteği için imzalama girdisi:

POST /b2b/v1/checkout-sessions/quick 1715990400 {"items":[...],"currency":"USD","success_url":"..."}

HMAC-SHA256(secret_key, signingString) ile imzalayın, hex olarak çıktı alın.

İsteği gönderin

server/create-session.ts
import { fetch } from "undici"; import { createHmac } from "node:crypto"; const PUBLIC_KEY = process.env.INFRAIO_PUBLIC_KEY!; // pk_test_… const SECRET_KEY = process.env.INFRAIO_SECRET_KEY!; // sk_test_… const BASE_URL = "https://api-dev.infraio.xyz"; const path = "/b2b/v1/checkout-sessions/quick"; const body = JSON.stringify({ items: [ { sku: "tee-large-blue", label: "Indigo Tee — L", unit_price: "49.00", quantity: 1, currency: "USD", image_url: "https://your-shop.test/img/tee.png", }, ], currency: "USD", customer_email: "[email protected]", success_url: "https://your-shop.test/return?status=success", cancel_url: "https://your-shop.test/return?status=cancel", external_ref: "ord_1234", // sizin sipariş id'niz; siparişte saklanır, webhook'larda yansıtılmaz — order_id üzerinden arayın expires_in: 1800, // saniye; varsayılan 30 dk idempotency_key: crypto.randomUUID(), // yeniden denemek güvenlidir }); const timestamp = Math.floor(Date.now() / 1000).toString(); const signingInput = ["POST", path, timestamp, body].join("\n"); const signature = createHmac("sha256", SECRET_KEY) .update(signingInput) .digest("hex"); const res = await fetch(`${BASE_URL}${path}`, { method: "POST", headers: { "Content-Type": "application/json", "X-Client-ID": PUBLIC_KEY, "X-Timestamp": timestamp, "X-Signature": signature, }, body, }); // Her API yanıtı bir zarfa sarılır — asıl yük `data` altındadır. // Üst düzeydeki `code`/`message`'ı sonuç işaretçisi olarak değerlendirin // (başarı için `201` / `"created"`). const { code, message, data } = await res.json() as { code: number; message: string; data: { session_key: string; checkout_url: string; order_id: string; expires_at: string }; }; const { session_key, checkout_url, order_id, expires_at } = data; // session_key + checkout_url'yi tarayıcıya gönderin. order_id ve expires_at // kendi kayıt tutmanız içindir.

Saat sapması önemlidir. Geçit, sunucu saatinden 5 dakikadan fazla sapan X-Timestamp’e sahip istekleri reddeder. Sunucularınızı NTP ile senkronize edin; uzun süre çalışan bir cron’un duvar saatine güvenmeyin.

3. Checkout’u açın (tarayıcı)

checkout.ts
import { loadInfraIo } from "@lartech/infraio-checkout-js"; const sdk = await loadInfraIo(process.env.NEXT_PUBLIC_INFRAIO_PK!); sdk.checkout({ sessionId: session_key, checkoutUrl: checkout_url, mode: "popup", // varsayılan onReady: () => console.log("checkout etkileşimli"), onSuccess: ({ sessionId }) => { // Yalnızca UX — aşağıdaki uyarıya bakın. Webhook yetkili olandır. location.assign("/thanks"); }, onCancel: () => console.log("alıcı popup'ı kapattı"), onError: (err) => console.error(err.code, err.message), });

4. Webhook’u işleyin (sunucu)

Webhook, para hareketinin tek yetkili sinyalidir. Tarayıcı callback’leri (onSuccess) bazı testnet zamanlamalarında gerçek bir ödeme olmadan tetiklenebilir — siparişi tarayıcı tarafı bir event’ten asla karşılamayın.

server/webhook.ts (Next.js App Router)
import { createHmac, timingSafeEqual } from "node:crypto"; const WEBHOOK_SECRET = process.env.INFRAIO_WEBHOOK_SECRET!; // whsec_… export async function POST(req: Request) { const raw = await req.text(); // HAM bayt, parse edilmemiş const signature = req.headers.get("x-signature") ?? ""; const timestamp = req.headers.get("x-timestamp") ?? ""; // İmza `${timestamp}.${raw}` üzerinedir — yalnızca gövde DEĞİLDİR. const expected = "sha256=" + createHmac("sha256", WEBHOOK_SECRET) .update(`${timestamp}.${raw}`) .digest("hex"); const a = Buffer.from(signature); const b = Buffer.from(expected); if (a.length !== b.length || !timingSafeEqual(a, b)) { return new Response("bad signature", { status: 400 }); } // HTTP gövdesi event başına veri nesnesinin TA KENDİSİDİR (Stripe stili // dış zarf yok). Event tipi + gönderim ID + timestamp başlıklarda yaşar. const eventType = req.headers.get("x-event") ?? ""; // örn. "payment.settled" const deliveryId = req.headers.get("idempotency-key") // X-Delivery'i yansıtır ?? req.headers.get("x-delivery") ?? ""; const payload = JSON.parse(raw); switch (eventType) { case "payment.settled": { // Payload order_id, payment_intent_id, tx_hash, amount_received, // confirmations, settlement token + network, vb. içerir. // Siparişten gelen `external_ref` DAHİL DEĞİLDİR — geriye eşleştirmek // gerekiyorsa sunucu tarafında order_id üzerinden arayın. const { order_id, tx_hash, amount_received, confirmations } = payload; // Siparişi idempotent şekilde ödendi olarak işaretleyin. Dedup // anahtarı olarak deliveryId (X-Delivery) kullanın — aynı gönderimin // tüm yeniden denemelerinde stabildir. 2xx olmayan yanıtlarda 6 kez // (1m / 5m / 15m / 1h / 6h) yeniden deneriz. break; } case "checkout.expired": { /* oturum TTL'i doldu — stoğu serbest bırakın */ break; } case "payment.refund.requested": { /* admin kuyruğunda gösterin */ break; } default: // İleriye dönük uyumluluk: event ekleyebiliriz. Kabul edin ve // hiçbir şey yapmayın. } return new Response("ok", { status: 200 }); }

Uç durumlar (gövde normalizasyonu, secret rotation, replay koruması) için Webhook’lar → İmza doğrulama sayfasına bakın.

5. Bir test ödemesi tetikleyin

Test modu oturumları gerçek testnet’lere karşı tahsil edilir (Sepolia, Base Sepolia, BSC Testnet, vb.) — mock chain yoktur. İlgili faucet’ten test fonu alın, ardından checkout sayfasının gösterdiği depozito adresine gönderin. Onaylar temizlendiğinde webhook tetiklenir (çoğu testnet’te 1 onay).

Sırada ne var