Payment Orchestrator
Kimlik Doğrulama

Kimlik Doğrulama

Payment Orchestrator API'si, çağrıyı kimin yaptığına (sunucunuz, alıcının tarayıcısı, herkese açık siteniz) ve işlemin ne kadar hassas olduğuna göre farklı kimlik doğrulama modelleri kullanır. Bu sayfa her modeli çalışan örneklerle anlatır, ardından her endpoint grubunu gerektirdiği modele eşler.

ModelNedirNerede kullanılır
Bearer erişim token'ı (at_live_…)Ed25519 anahtarınızla bastığınız kısa ömürlü tokenListeleme, sorgular, subscription & marketplace CRUD
Step-Up (Bearer + Ed25519 imza)Para hareketi için imzalı istekIntent'ler, direct çekimler, capture/void/refund
İmzalı istek (yalnız Ed25519 imza)Bearer token olmadan, isteğin kendisini API anahtarınızla imzalarsınızÖdeme linkleri (/payments/links/*)
Form token + session-proof cookieKısa ömürlü alıcı tarafı kimlik bilgileri/payments/form/* (hosted checkout)
Publishable key (mk_live_pk_…) + Origin allow-listTarayıcıya konması güvenli key/api/public/v1/subscription/* (pricing catalog)
Idempotency-Key headerÇift çekim korumasıTüm ödeme POST'ları

Tüm örnekler için base URL: https://api-gateway.lunixi.com/api/v1.

Bearer erişim token'ı

Sunucudan sunucuya çağrıları kısa ömürlü bir erişim token'ı doğrular. Token'ı statik bir anahtar olarak saklamazsınız — kayıtlı Ed25519 anahtarınızla imzalayıp POST /api/v1/auth/token'dan basarsınız.

Ed25519 özel anahtar  ──imzala──▶  POST /api/v1/auth/token  ──▶  at_live_…  (~5 dk)

Aldığınız token'ı Authorization header'ında gönderin:

curl "https://api-gateway.lunixi.com/api/v1/payments?limit=20" \
  -H "Authorization: Bearer at_live_5f3e2b1a..."

Yukarıdaki örnek yalnız limit gönderiyor. GET /api/v1/payments cursor da kabul eder — sayfalamak için önerilen yol odur. Endpoint hâlâ page kabul ediyor ama o deprecated'dir: kullanıldığında yanıt Deprecation ve Sunset başlıkları taşır. → Sayfalama

⚠️

Uzun ömürlü secret'ınız token değil, Ed25519 özel anahtarınızdır — ve o hiçbir zaman telde gitmez. Anahtarı tarayıcıya, mobil uygulamaya veya herkese açık bir depoya asla koymayın. Sızarsa panelden kid'i iptal edip yeni bir çift üretin.

Token ömrü tipik olarak 5 dakikadır. Her çağrıda yeni token basmayın — expires_at'e bakarak önbellekte tutun. İmzalama ve kanonik dize ayrıntısı: Kimlik Doğrulama

Step-Up: para hareketi için imzalı istekler

Para hareketi yapan her endpoint — intent oluşturma, direct çekim, capture, void, refund — Step-Up auth ister: geçerli bir Bearer key ve isteğin üzerine bir Ed25519 imzası. Secret key'iniz sızsa bile, saldırgan özel imza anahtarınız olmadan para hareket ettiremez.

Bir Step-Up isteği şu header'ları taşır:

HeaderDeğer
AuthorizationBearer at_live_…
X-Key-IdKayıtlı Ed25519 public key'inizin key id'si (kid)
X-DateISO 8601 istek zaman damgası — sunucu saatine göre ±5 dakika içinde olmalı
X-Nonceİstek başına benzersiz değer (örn. UUID) — tek kullanımlık, tekrarlar reddedilir
DigestHam JSON body'nin SHA-256=<base64> hash'i (body varsa zorunlu)
X-SignatureAşağıdaki kanonik string üzerine Base64 Ed25519 imzası

İmzalayacağınız string; method, tam istek path'i ve header'lardan \n ile birleştirilerek oluşturulur:

POST
/api/v1/payments/intents
X-Date:2026-07-06T12:00:00.000Z
X-Nonce:9f8d2c4e-1a3b-4c5d-8e7f-0a1b2c3d4e5f
Digest:SHA-256=k6I5cUt...=
import { createHash, createPrivateKey, sign, randomUUID } from 'node:crypto';
 
const body = JSON.stringify({
  amount: 10050,               // minor unit (kuruş) — ₺100,50
  currency: 'TRY',
  orderId: 'ORD-9988',
});
 
const digest = 'SHA-256=' + createHash('sha256').update(body).digest('base64');
const date = new Date().toISOString();
const nonce = randomUUID();
 
const canonical = [
  'POST',
  '/api/v1/payments/intents',
  `X-Date:${date}`,
  `X-Nonce:${nonce}`,
  `Digest:${digest}`,
].join('\n');
 
const signature = sign(
  null, // Ed25519 — digest algoritması yok
  Buffer.from(canonical),
  createPrivateKey(process.env.LUNIXI_SIGNING_KEY_PEM),
).toString('base64');
 
const res = await fetch('https://api-gateway.lunixi.com/api/v1/payments/intents', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LUNIXI_SECRET_KEY}`,
    'Content-Type': 'application/json',
    'X-Key-Id': process.env.LUNIXI_KEY_ID,
    'X-Date': date,
    'X-Nonce': nonce,
    'Digest': digest,
    'X-Signature': signature,
    'Idempotency-Key': randomUUID(),
  },
  body,
});

Bearer key ile imza anahtarı aynı merchant'a ve aynı environment'a ait olmalıdır — uyuşmazlık 403 AUTH_MERCHANT_MISMATCH / AUTH_ENVIRONMENT_MISMATCH ile reddedilir.

Checkout form token & session-proof cookie (alıcı tarafı)

Hosted checkout formu, key'lerinizi hiç ifşa etmeden alıcının tarayıcısını doğrular:

  1. Sunucunuz Step-Up auth ile bir intent oluşturur. Yanıt, allowedOrigin'inize bağlı, kısa ömürlü (~15 dakika) bir form token içerir.
  2. Form bu token ile POST /payments/form/live-analyze çağırır; yanıt, tarayıcı oturumunu bağlayan bir session-proof cookie set eder.
  3. Her /payments/form/* çağrısı token'ı taşır; karta dokunan çağrılar (/form/tokenize, /form/2d, /form/3d) ek olarak session-proof cookie'yi ister.
curl -X POST "https://api-gateway.lunixi.com/api/v1/payments/form/live-analyze" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{ "token": "<intent-ten-gelen-form-token>" }'

https://cdn.lunixi.com üzerinden Lunixi checkout SDK'sını kullanıyorsanız token aktarımı, live-analyze çağrısı ve cookie yönetimi otomatik yapılır — bu kimlik bilgilerini hiç yönetmezsiniz. Bkz. Hızlı Başlangıç.

Publishable key + Origin allow-list

Publishable key (mk_live_pk_…) herkese açık sitenize gömülmesi güvenli olan key'dir. Yalnızca salt-okunur public catalog endpointlerini açar ve istekler ayrıca kayıtlı Origin allow-list'inize karşı denetlenir — çalınan bir key başka bir domain'den işe yaramaz.

curl "https://api-gateway.lunixi.com/api/public/v1/subscription/plans" \
  -H "Authorization: Bearer mk_live_pk_xxxxxxxxxxxx" \
  -H "Origin: https://shop.example.com"

/api/public/v1/subscription/plans|products|branding tarafından kullanılır — sitenize pricing gömmek için. Bkz. Pricing & Portal SDK.

Idempotency

Her ödeme POST'unda bir Idempotency-Key header'ı gönderin (benzersiz herhangi bir string, örn. UUID). Aynı key tekrar gelirse — ağ zaman aşımı, çift tıklanan buton, tekrar deneyen bir job — API çifte çekim yapmak yerine orijinal sonucu döner. Tekilleştirme Redis ile, Redis erişilemezse veritabanı benzersizliğiyle desteklenir.

curl -X POST "https://api-gateway.lunixi.com/api/v1/payments/pay_01JZ8K4W9X2R/refund" \
  -H "Authorization: Bearer at_live_5f3e2b1a..." \
  -H "Idempotency-Key: refund-ORD-9988-1" \
  ... # Step-Up imza header'ları
  -d '{ "amount": 5000 }'
⚠️

İsteği değil işlemi tanımlayan bir key kullanın — örn. refund-ORD-9988-1. Her denemede yeni rastgele key üretmek korumayı boşa çıkarır.

Hangi endpoint hangi modeli ister

Endpoint grubuAuth modeli
POST /payments/intents, POST /payments/marketplace/intentsStep-Up
POST /payments/direct/payment, GET /payments/methodsStep-Up
POST /payments/:id/capture, /:id/void, /:id/refundStep-Up
GET /payments, GET /payments/:id, analyticsBearer
POST /bin/info, GET /bin/card-taxonomy, POST /bin/installmentsBearer
/chargebacks/*Bearer
/payments/form/* (2d, 3d, tokenize, live-analyze, bin)Form token (karta dokunan çağrılarda + session-proof cookie)
GET /payments/threed/:token, /payments/threed/callback/:tokenPublic — path'teki tek kullanımlık token güvenlik sınırıdır
/payments/links/* (oluşturma, listeleme, güncelleme, gönderme, QR)İmzalı istek — Ed25519 imza başlıkları ve anahtarın payment-link:* yetkisi; Authorization gerekmez, panel oturumu kabul edilmez — bkz. Link Oluşturma
/api/public/v1/pay/* (ödeme linki sayfası)Public — alıcının tarayıcısı çağırır; anahtar taşımaz, bot kontrolü (Turnstile) ve kısa ömürlü ödeme oturumu çerezi ile korunur. Sizin çağırmanız gerekmez — bkz. Ödeme Sayfası
/marketplace/* (dealers, komisyonlar, payout'lar)Bearer
/marketplace/portal/* (satıcı onboarding'i)Marketplace onboarding token (X-Marketplace-Token) — bkz. Satıcı Onboarding
/api/v1/subscriptions/*Bearer
/api/public/v1/subscription/*Publishable key + Origin
/api/portal/v1/* (son müşteri self-service)Portal session (portal token → OTP → session JWT) — bkz. Müşteri Portalı

Hatalar

Status / kodAnlamıNe yapmalı
401 AUTH_HEADERS_MISSINGX-Key-Id, X-Date, X-Nonce, X-Signature'dan biri eksikDört Step-Up header'ının hepsini gönderin
401 INVALID_DATEX-Date ±5 dakikalık pencerenin dışındaSunucu saatinizi senkronlayın (NTP) ve tekrar deneyin
401 DIGEST_MISSING / INVALID_DIGESTBody var ama Digest eksik veya yanlışGönderdiğiniz ham body byte'larını hash'leyin
401 INVALID_SIGNATUREİmza doğrulanamadıKanonik string'i yeniden kurun — method, path, header'lar, bu sırayla, \n ile
401 (nonce tekrarı)X-Nonce daha önce kullanıldıHer istek için yeni nonce üretin
403 AUTH_MERCHANT_MISMATCHBearer key ile imza anahtarı farklı merchant'lara aitAynı merchant hesabının key'lerini kullanın
403 AUTH_ENVIRONMENT_MISMATCHTest key ile live key karışmışTest ve live kimlik bilgilerini ayrı tutun
403 IP_NOT_ALLOWEDÇağıran IP, key'in IP allow-list'inde değilPanelden allow-list'i güncelleyin

Sonraki adımlar