Skip to Content
Kavramlarİadeler

İadeler

Bir Refund, Order üzerindeki bir bayrak değil, birinci sınıf bir varlıktır. Kısmi iadeler verebilir, aynı Order’a karşı birden fazla iade yapabilir veya aynı akışta iade + yeniden tahsilat gerçekleştirebilirsiniz.

İade kaydının var olabileceği iki yol:

AkışFormu kim doldururAuthŞu durumda başlar
Satıcı tarafından başlatılanPaneliniz / backend’inizHMAC (sk_…)Hemen APPROVED
Müşteri tarafından başlatılanAlıcı, barındırılan sayfamızdaTek kullanımlık token (kimlik bilgisi yok)PENDING — onaylarsınız veya yapılandırmanız otomatik onaylıyorsa kısa devre yapar

Müşteri tarafından başlatılan akış, kısa ömürlü bir iade-talep token kullanır. Bir token üretirsiniz (B2B veya panel), URL’yi alıcıya nasıl isterseniz iletirsiniz ve alıcı iade detaylarını checkout.infraio.xyz/refund-request/:token üzerinde tamamlar. Alıcı asla API’nize dokunmaz ve satıcı anahtarınızı asla görmez.

İade yaşam döngüsü

DurumAnlamı
PENDINGİade kaydedildi, onay bekleniyor. Müşteri tarafından başlatılan iadeler her zaman buradan başlar.
APPROVEDYürütme için onaylı. Satıcı tarafından başlatılan iadeler doğrudan buraya atlar.
REJECTEDİade reddedildi. Sipariş durumu değişmez.
EXECUTEDZincir üstü transfer onaylandı. Order PARTIALLY_REFUNDED / REFUNDED durumuna geçer.

Satıcı tarafından başlatılan

İade etmeye karar verirsiniz (örn. alıcı sohbet üzerinden şikayet etti). Satıcı-tarafından-başlatılan uç noktayı çağırın — incelemeyi atlar ve hemen APPROVED durumuna geçer.

POST /b2b/v1/merchants/{merchant_id}/refunds { "order_id": "ord_01J5K…", "amount": "49.00", // kısmi veya tam, siparişin gösterim para biriminde "reason": "customer complaint #4521", "refund_to_address": "0xBUYER…", // kripto raylar için gereklidir "refund_network": "polygon", // network slug; bkz. Kavramlar → Zincirler "refund_token_address":"0xUSDC_CONTRACT" // geri ödenen ERC-20 sözleşmesi; genellikle orijinal token }

İade isteğinde currency alanı yoktur — iadeler her zaman siparişin gösterim para birimini miras alır (bugün USD). (refund_to_address, refund_network, refund_token_address) üçlüsü zincir üstü hedeftir; payment-service kripto saga’sını yürütmek için bunları kullanır. Fiat raylar için yok sayılırlar (provider tarafından otomatik yönlendirilir).

Sipariş, zincir üstü transferi yürütene kadar mevcut durumunu korur (bkz. Bir kripto iadesini yürütme).


Müşteri tarafından başlatılan — iade-talep token’ları

Alıcı iade formunu bizim barındırılan sayfamızda doldurur, sizinkinde değil. Tek işiniz bir token üretmek ve URL’yi iletmek.

Token yaşam döngüsü

DurumAnlamıMüşteri URL’si neyi render eder
ACTIVEToken aktif, now < expires_atİade formu (refund_to_address, reason, amount, isteğe bağlı not → metadata.note)
SUBMITTEDAlıcı formu tamamladı; bir Refund satırı var/r/:linkToken’ı yansıtan durum kartı
EXPIRED_UNUSEDAlıcı göndermeden TTL geçtiUyarı: “Bu bağlantının süresi doldu. Yeni bir tane talep edin”
RENEWAL_REQUESTEDAlıcı yeni bir bağlantı istediBekleme bildirimi: “Satıcınıza bildirildi”
RENEWEDSatıcı yenilemeyi onayladı ve bir yedek üretti”Bu bağlantı değiştirildi — yeni bağlantı için e-postanıza bakın” (yeni token, yönlendirilmiş bağlantı saldırılarını engellemek için burada gösterilmez)
CANCELEDSatıcı token’ı panelden iptal ettiDüz “Bu iade talebi iptal edildi”

Token’lar tek kullanımlıktır. SUBMITTED olduktan sonra URL, alıcının durumu kontrol etmesi için geçerli kalır ama tekrar göndermek için kullanılamaz. Aynı siparişe karşı ikinci bir iade vermek için yeni bir token üretin.

TTL varsayılanları

Üretim kaynağıVarsayılan TTLNeden
POST /b2b/v1/merchants/{merchant_id}/refund-requests (HMAC)30 dakikaProgramatik — alıcıya hemen verildiği varsayılır.
POST /payment/v1/merchants/{merchant_id}/refund-requests (panel JWT’si)24 saatManuel — satıcı URL’yi bir e-posta / SMS’e yapıştırır.

Geçersiz kılmak isterseniz her iki uç nokta da gövde alanı olarak ttl_seconds kabul eder. Sunucu tarafında uygulanan sert bir min/max sınırı bugün yoktur — yaygın değerler 1 dakika ile 7 gün arasındadır. Alıcıları şaşırtmamak veya iptal edilen token’lar üzerinde kapasite tutmamak için bu aralık içinde kalın.

B2B API üzerinden üretim

Bir destek konuşmasından hemen sonra, sipariş iptal akışından vb. programatik olarak bir iade bağlantısı üretmek isteyen backend’ler için.

POST /b2b/v1/merchants/{merchant_id}/refund-requests Content-Type: application/json X-Client-ID: pk_live_… X-Timestamp: 1729536000 X-Signature: 4f2a1b9c8d3e2f1a0b9c8d7e6f5a4b3c… { "ref_type": "order_id", // gerekli: order_id | order_number | session_id | session_key "ref_value": "ord_01J5K…", // gerekli: ref_type ile eşleşir "amount": "49.00", // gerekli — alıcının gönderebileceği maksimumu kilitler "ttl_seconds": 1800, // opsiyonel — varsayılan 1800 (30 dk) "metadata": { "support_ticket": "4521" }, // opsiyonel — Stripe stili anahtar/değer "hide_summary": false, // barındırılan form için opsiyonel UI bayrakları "hide_header": false }

B2B istek imzası sha256= öneki olmadan ham küçük harf hex’tir — bu önek yalnızca gelen webhook imzalarında görünür (Infraio → sunucunuz). Giden B2B imzalama dizesi METHOD\nPATH\nTIMESTAMP\nBODY şeklindedir; kanonik algoritma için bkz. Kimlik doğrulama.

Tutar üretim gövdesinde vardır ve gereklidir. Alıcının form üzerinde gönderebileceği tavanı kilitler — daha azı için gönderebilirler ama asla daha fazlası için değil. (Kısmi iadeler için kısmi tutarla bir token üretin; tam iadeler için sipariş toplamı ile üretin.)

Geriye dönük uyumluluk için eski { "order_id": "..." } şekli hâlâ kabul edilir — dahili olarak (ref_type=order_id, ref_value=...)’a eşlenir — ama yeni entegrasyonlar açık ref_type + ref_value çiftini kullanmalıdır.

Yanıt:

{ "token": "rfqt_01J7P3Q9R…", "refund_url": "https://checkout.infraio.xyz/refund-request/rfqt_01J7P3Q9R…", "expires_at": "2026-05-28T10:32:00Z" }

Webhook uç noktalarınıza refund_request.created tetikler (böylece bir sipariş için hangi token’ın şu anda aktif olduğunu loglayabilir / denetim yapabilirsiniz).

Panel üzerinden üretim

Satıcı panelindeki  Issue Refund modal’ı bir geçiş anahtarı sunar: Şimdi yürüt vs Müşteriye bağlantı gönder. İkincisini seçmek arka planda POST /payment/v1/merchants/{merchant_id}/refund-requests çağırır (JWT ile doğrulanır, yukarıdaki B2B ile aynı gövde şekli), ardından size URL’yi bir kopyalama butonu ve QR kodu ile gösterir. Hangi kanal mantıklıysa yapıştırın — e-posta, destek sohbeti, SMS.

JavaScript SDK üzerinden — openRefundRequest

Yığınınızda zaten @lartech/infraio-checkout-js varsa ve alıcının iadeyi harici bir URL aracılığıyla değil, kendi sayfa akışınızın içinde tamamlamasını istiyorsanız, B2B üretimini sdk.openRefundRequest() ile eşleyin:

// Sunucu tarafı: token'ı üret const { token } = await fetch("/api/mint-refund-token", { method: "POST" }).then(r => r.json()); // İstemci tarafı: barındırılan formu aç const sdk = await loadInfraIo("pk_live_yourkeyhere"); const close = sdk.openRefundRequest({ token, mode: "popup", // veya "redirect" | "embed" onSuccess: ({ linkToken, refundId }) => { // linkToken → /r/:linkToken alıcı durum sayfası. // refundId → approve / reject için B2B API referansı. window.location.href = `/r/${linkToken}`; }, onCancel: () => { /* alıcı popup'ı kapattı */ }, onError: (err) => { /* bkz. SDK referansı */ }, });

Tam seçenek tablosu için SDK referansı → sdk.openRefundRequest() sayfasına bakın.

Müşteri yenilemesi — alıcı tarafından yönlendirilen yeniden-üretme

Alıcı URL’yi token süresi dolduktan sonra açarsa, sayfa formun yerine bir Yeni bağlantı talep et butonu sunar. Tıklamak:

  1. /pub/v1/refund-requests/:token/request-renewal adresine POST eder (kimlik bilgisi yok — token’ın kendisi bearer-kanıtıdır)
  2. Opsiyonel olarak alıcının satıcı için bırakabileceği bir serbest metin not (customer_note) yakalar
  3. Token’ı RENEWAL_REQUESTED’a geçirir ve webhook’unuza refund_request.renewal_requested tetikler

Paneliniz yenileme-talepleri widget’ında bir rozet gösterir. Onaylayın (tek tık) ve sistem yeni bir ACTIVE token üretir, refund_request.renewed tetikler ve yeniden göndermek için yeni URL’yi kopyalamanıza izin verir. Eski URL erişilebilir kalır ama “Değiştirildi — e-postanıza bakın” gösterir, böylece eski URL’nin yönlendirilmiş bir kopyası yeniyi çekmek için kullanılamaz.


Bir kripto iadesini yürütme

API niyeti kaydeder — fonları hareket ettirmez. Siz satıcı cüzdanınızdan zincir üstü transferi imzalar ve yayar, ardından tx hash’i iade kaydına damgalarsınız:

POST /b2b/v1/refunds/:refund_id/submit-tx Content-Type: application/json { "tx_hash": "0xabcd…", "network": "ethereum", "token_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }

Üç gövde alanının da olması gereklidir: aynı tx hash farklı zincirlerde var olabilir ve orijinal ödemenin tahsil edildiği stablecoin’den farklı bir stablecoin’de iade yapabilirsiniz.

Zincir izleyici, bu tx’in yapılandırılmış onay sayısını temizlediğini gördüğünde (bkz. Zincirler ve varlıklar), iade EXECUTED durumuna geçer ve Order’ın iade-toplamı güncellenir.

Satıcı fonlarının saklamasını kasıtlı olarak yapmıyoruz, bu da iadeleri sizin adınıza yürütemeyeceğimiz anlamına gelir. Zincir üstü gönderimi admin araçlarınıza entegre edin — bir multisig veya hot cüzdandan eth_sendRawTransaction, tx hash’ini iade API’sine gönderme ile biten bir iş akışı.


Webhook event’leri

İade alt sistemi iki event ailesini tetikler:

Token yaşam döngüsü (refund_request.*)

EventŞu durumda tetiklenir
refund_request.createdBir token üretildi — data.source b2b / dashboard / renewal
refund_request.renewal_requestedBir alıcı token süresi dolduktan sonra “Yeni bağlantı talep et” butonuna tıkladı. Bu event’e abone olun — satıcının harekete geçme zamanıdır.
refund_request.renewedBir yenilemeyi onayladınız ve yeni bir token eskisini değiştirdi. data.old_token / data.new_token denetim zincirini oluşturur.
refund_request.canceledBir token’ı panelden CANCELED’a geçirdiniz. Idempotent — yalnızca ilk geçiş bir event yayar. data.reason opsiyonel satıcı notudur.

İade yaşam döngüsü (payment.refund.*)

EventŞu durumda tetiklenir
payment.refund.requestedYeni bir Refund satırı var — herhangi bir kaynaktan (form gönderimi, satıcı tarafından başlatılan API, panel).
payment.refund.approvedİade onaylandı — ya otomatik olarak (satıcı tarafından başlatılan) ya da bekleyen bir iadeye /approve çağırdıktan sonra.
payment.refund.rejectedBekleyen bir iadeye /reject çağırdınız.
payment.refund.executedFonlar hareket etti (kripto tx hash’iniz gerekli onaylara ulaştı).

payment.failed bir iade için tetiklenmez — iadeler kendi event serisine sahiptir, payment.refund.* öneki altında.

Sırada ne var