Cüzdan
Hızlı Başlangıç

Hızlı Başlangıç

Bu uçları kim çağırır?Dış API (s2s)
Taban yol
/api/v1/wallet
Kimlik
Ed25519 istek imzası — X-Key-Id, X-Date, X-Nonce, Digest (body varsa), X-Signature. Zaman penceresi ±5 dk, nonce tek kullanımlık, anahtarda IP allow-list olabilir.
Yetki
Anahtarınız cüzdan ürününü ve çağrının gerektirdiği cüzdan iznini taşımalıdır; izni olmayan çağrı 403 WALLET_INSUFFICIENT_SCOPE alır. Uç başına izinler: Anahtar izinleri.
Çapraz yüzey
Bu uçlar zaten s2s yüzeyindedir — kendi sunucunuzdan imzalı olarak çağırabilirsiniz.

Bu rehber sizi sıfırdan çalışan bir cüzdan akışına götürür: kullanıcı oluşturma → bakiye yükleme → transfer → sonucu doğrulama. Tamamı bugün üretimde çalışan yollardan geçer; bağlı sağlayıcı gerektiren hiçbir adım yoktur.

Tüm tutarlar minor-unit string'dir: "amount": "10050" = ₺100,50. Tüm istekler Ed25519 imzalıdır — aşağıdaki örneklerde imza header'ları … ile kısaltılmıştır. İstek body'lerini boşluksuz JSON olarak (satır sonu ve fazladan boşluk olmadan) gönderin ve Digest değerini tam olarak bu metin üzerinden hesaplayın; aşağıdaki body'ler yalnız okunabilirlik için birkaç satıra yayılmıştır.

İmzalamayı doğrulayın

Para hareketine geçmeden önce imzanızın çalıştığını en basit uçla kanıtlayın:

curl "https://api-gateway.lunixi.com/api/v1/wallet/ping" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" -H "X-Nonce: $NONCE" -H "X-Signature: $SIG"

Bu çağrı için anahtarınızda bir kurulum izni (wallet:program:manage veya wallet:enduser:manage) bulunmalıdır. 200 almadan devam etmeyin. Sorun varsa Kimlik Doğrulama → Hata kodları.

Programınızı öğrenin

curl "https://api-gateway.lunixi.com/api/v1/wallet/programs/me" \
  -H "X-Key-Id: …" -H "X-Date: …" -H "X-Nonce: …" -H "X-Signature: …"

Programınızın id değerini not edin: son kullanıcı oluştururken ve program alan diğer çağrılarda bu değeri programId olarak gönderirsiniz.

Son kullanıcı oluşturun

Kullanıcı program içinde telefonla tekildir — aynı telefonla yeni bir anahtarla gönderilen ikinci çağrı yeni kullanıcı üretmez, 409 WALLET_ENDUSER_EXISTS döner; aynı Idempotency-Key ile tekrar ise ilk yanıtı döndürür. Tüm alanlar ve kurallar: Son Kullanıcı Oluşturma.

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/end-users" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: signup-crm-88213" \
  -H "X-Key-Id: …" -H "X-Date: …" -H "X-Nonce: …" -H "Digest: …" -H "X-Signature: …" \
  -d '{
    "programId": "5b9e2f3a-7c41-4d8e-a6f2-9e1b3c4d5f60",
    "accountType": "PERSONAL",
    "phone": "+905321234567",
    "externalCustomerId": "crm-88213",
    "displayName": "Ayşe Y."
  }'

Yanıt, kullanıcıyla birlikte varsayılan cüzdanı ve hesaplarını da döner:

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "endUser": { "id": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34", "accountType": "PERSONAL", "status": "ACTIVE" },
    "defaultWallet": {
      "id": "1e7f9a3b-5c2d-4a8e-b6f1-3d9c0e2a7b58",
      "walletNo": "5810763412",
      "name": "Cüzdanım",
      "isDefault": true,
      "accounts": [
        { "id": "c2a5e8f1-9d3b-4c7a-8e6f-5b1d2a9c0e47", "currency": "TRY", "fullWalletNo": "58107634125000", "status": "ACTIVE" }
      ]
    }
  }
}

externalCustomerId sizin kimliğinizdir. Bizim id'lerimizi saklamak istemiyorsanız kullanıcıya GET /wallet/end-users/by-external/crm-88213?programId=… ile ulaşabilirsiniz.

Gerekiyorsa ek hesap açın

Varsayılan cüzdan tek bir hesapla, programınızın ana para biriminde (ya da istekte defaultCurrency ile verdiğiniz para biriminde) açılır. Farklı bir para birimi gerekiyorsa:

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/wallets/1e7f9a3b-5c2d-4a8e-b6f1-3d9c0e2a7b58/accounts" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: acct-crm-88213-usd" \
  -H "X-Key-Id: …" -H "X-Signature: …" \
  -d '{ "currency": "USD" }'

Kartla bakiye yükleyin

Kart yüklemesi ödeme altyapısına delege edilir: yanıt size ya hosted checkout içeriği ya da 3D Secure yönlendirmesi verir.

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/topups/card" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: topup-crm-88213-1" \
  -H "X-Key-Id: …" -H "X-Signature: …" \
  -d '{
    "creditWalletAccountId": "c2a5e8f1-9d3b-4c7a-8e6f-5b1d2a9c0e47",
    "amount": "25000",
    "currency": "TRY",
    "returnUrl": "https://app.acme.com/wallet/topup/result"
  }'
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "operationId": "4f1b8d2e-6a9c-4b3e-8f7d-1c5e9a2b6d08",
    "paymentId": "9c6f2b1a-4e8d-4a3f-b5e6-2d7c1a9b8e30",
    "status": "INITIALIZED",
    "checkoutFormContent": "<script …>",
    "redirectUrl": ""
  }
}

checkoutFormContent'i kullanıcının tarayıcısında mount edin; kart bilgisi sizin sunucunuza hiç uğramaz. Kullanıcı ödemeyi tamamladığında operasyon COMPLETED olur ve wallet.topup.completed webhook'u düşer.

⚠️

Yükleme sonucunu returnUrl'e dönen kullanıcıdan öğrenmeyin. Tarayıcı geri dönmeyebilir. Doğru kaynak webhook'tur; teyit için GET /wallet/topups/{operationId}.

Bakiyeyi kontrol edin

curl "https://api-gateway.lunixi.com/api/v1/wallet/end-users/8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34/balances" \
  -H "X-Key-Id: …" -H "X-Signature: …"
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "balances": [
      {
        "walletAccountId": "c2a5e8f1-9d3b-4c7a-8e6f-5b1d2a9c0e47",
        "currency": "TRY",
        "balance": "25000",
        "fullWalletNo": "58107634125000"
      }
    ]
  }
}

Transferi önce fiyatlandırın

Para çıkaran işlemlerde önce quote çağırın — kullanıcıya ücreti hesaptan düşülmeden önce göstermek zorundasınız.

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/transfers/w2w/quote" \
  -H "Content-Type: application/json" \
  -H "X-Key-Id: …" -H "X-Signature: …" \
  -d '{
    "endUserId": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34",
    "sourceWalletAccountId": "c2a5e8f1-9d3b-4c7a-8e6f-5b1d2a9c0e47",
    "destinationPhone": "+905339876543",
    "amount": "10050",
    "currency": "TRY"
  }'
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "feeTotal": "250",
    "taxTotal": "125",
    "totalCharge": "10425",
    "requiredAmount": "10425",
    "maskedDestinationName": "Meh*** Ö***",
    "sourceBalance": "25000",
    "sufficientBalance": true,
    "limitBlocked": false,
    "scheduleVersionId": "2d8b5e1c-7f4a-4c9e-a3b6-8e1f5c2d9a74"
  }
}

sufficientBalance: false ya da limitBlocked: true ise transferi başlatmayın — kullanıcıya nedeni gösterin. maskedDestinationName alıcının doğru kişi olduğunu teyit ettirmek içindir.

Transferi başlatın

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/transfers/w2w" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: p2p-crm-88213-1" \
  -H "X-Key-Id: …" -H "X-Signature: …" \
  -d '{
    "endUserId": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34",
    "sourceWalletAccountId": "c2a5e8f1-9d3b-4c7a-8e6f-5b1d2a9c0e47",
    "destinationPhone": "+905339876543",
    "amount": "10050",
    "currency": "TRY",
    "scheduleVersionId": "2d8b5e1c-7f4a-4c9e-a3b6-8e1f5c2d9a74",
    "otpDestination": "+905321234567",
    "otpChannel": "SMS"
  }'
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "operationId": "7a3e9c1d-2b4f-4e8a-9d6c-0f5b8e2a1c93",
    "status": "CHALLENGED",
    "otpRequired": true,
    "otpChannel": "SMS",
    "integrityHash": "9c1f…",
    "nonce": "4b82…"
  }
}

Fon rezerve edildi, para henüz taşınmadı. otpRequired: true ise kullanıcıya kod soruyorsunuz.

Transferi tamamlayın

curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/transfers/w2w/7a3e9c1d-2b4f-4e8a-9d6c-0f5b8e2a1c93/complete" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: p2p-crm-88213-1-complete" \
  -H "X-Key-Id: …" -H "X-Signature: …" \
  -d '{
    "endUserId": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34",
    "operationId": "7a3e9c1d-2b4f-4e8a-9d6c-0f5b8e2a1c93",
    "integrityHash": "9c1f…",
    "nonce": "4b82…",
    "otpCode": "482913"
  }'
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "operationId": "7a3e9c1d-2b4f-4e8a-9d6c-0f5b8e2a1c93",
    "status": "COMPLETED",
    "ledgerTxnRef": "ltx_01J8ZU…",
    "receiptUrl": "https://api-gateway.lunixi.com/api/v1/wallet/operations/7a3e9c1d-2b4f-4e8a-9d6c-0f5b8e2a1c93/receipt"
  }
}
⚠️

integrityHash ve nonce bir önceki adımdan birebir taşınmalıdır. nonce tek kullanımlıktır; complete hata verirse aynı nonce ile tekrar denemeyin, operasyonu sorgulayın.

Webhook'u bağlayın

Asenkron sonuçları polling ile değil webhook ile öğrenin. Panelden endpoint'inizi tanımlayın ve şu olayları dinleyin:

OlayNe zaman
wallet.topup.completedKart/havale yüklemesi bakiyeye yansıdı
wallet.topup.failedYükleme başarısız
wallet.transfer.completedTransfer tamamlandı
wallet.transfer.failedTransfer başarısız, rezervasyon çözüldü

Zarf ve imza doğrulaması: Webhook'lar.

Sonraki adımlar