<!-- Source: https://docs.infraio.xyz/tr/get-started/quickstart -->
<!-- Last updated: 2026-10-04 -->

# 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.

> **Note:**
>
> Bir **test** API anahtar çiftine (`pk_test_…` + `sk_test_…`) ve bir
> **webhook imzalama secret'ına** (`whsec_…`) ihtiyacınız var. Bunları
> [satıcı panelinde](https://app.infraio.xyz) **Geliştiriciler → API
> anahtarları** ve **Geliştiriciler → Webhook'lar** altında oluşturun.

## 1. Tarayıcı SDK'sını yükleyin

**npm**

```bash
npm install @lartech/infraio-checkout-js
```

**pnpm**

```bash
pnpm add @lartech/infraio-checkout-js
```

**yarn**

```bash
yarn add @lartech/infraio-checkout-js
```

**bun**

```bash
bun add @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

```ts filename="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: "buyer@example.com",
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.
```

> **Warning:**
>
> Saat sapması önemlidir. API, 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ı)

**Popup**

```ts filename="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),
});
```

**Yönlendirme**

```ts filename="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: "redirect",
});
// Tarayıcı checkout.infraio.xyz'ye yönelir; alıcı, oturum oluşturma
// payload'undaki `success_url` / `cancel_url`'nize geri döner.
```

**Gömme**

```ts filename="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: "embed",
  container: "#checkout-container",   // DOM hedefiniz
  onReady: () => /* iframe yüklendi */ {},
});
```

## 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.

```ts filename="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](https://docs.infraio.xyz/tr/webhooks/signature-verification) 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).

TRON Nile, Solana Devnet ve TON Testnet'te (yakında) depozito adresi yoktur: alıcı, checkout sayfası üzerinden bir cüzdanla öder. Bkz. [Doğrudan cüzdana ödeme yapan ağlar](https://docs.infraio.xyz/tr/concepts/chains#doğrudan-cüzdana-ödeme-yapan-ağlar).

## Sırada ne var

- [Kavramlar → Oturumlar](https://docs.infraio.xyz/tr/concepts/sessions) — üç katmanlı veri modeli
  (CheckoutSession + Order + PaymentIntent).
- [Kavramlar → Zincirler ve varlıklar](https://docs.infraio.xyz/tr/concepts/chains) — hangi ağ ve
  tokenlerin canlı ve test ortamında desteklendiği.
- [Webhook'lar → Genel bakış](https://docs.infraio.xyz/tr/webhooks/overview) — her event tipi ve
  onu neyin tetiklediği.
- [Güvenlik → API anahtarları](https://docs.infraio.xyz/tr/security/api-keys) — scope'lar, rotation,
  rate limit'ler.
