MercanPay Blog

order_id ile Fatura Sipariş Eşleştirme ve Çift Fatura Önleme

Fatura sipariş eşleştirme için order_id nasıl kullanılır? İdempotent fatura oluşturma, 409 çakışması, yeniden deneme ve mutabakat için pratik rehber.

Yayınlanma: 5 Kasım 20265 dk okumaRead in English
order_id ile Fatura Sipariş Eşleştirme ve Çift Fatura Önleme

Fatura sipariş eşleştirme, kripto ödeme entegrasyonunun en sessiz ama en kritik parçasıdır. Müşteri ödeme yaptığında hangi siparişin kapanacağını kesin olarak bilmeniz, ağ hatasında tekrar denediğinizde ikinci bir fatura açılmaması ve ay sonunda kayıtların birebir tutması gerekir. MercanPay'de bunun anahtarı tek bir alandır: order_id. Bu yazıda order_id'nin nasıl çalıştığını, idempotent davranışını ve sık yapılan hataları ele alıyoruz.

Fatura sipariş eşleştirmede order_id neden önemlidir?

order_id, fatura oluştururken gönderdiğiniz sizin kendi sipariş numaranızdır. En fazla 128 karakter olabilir ve isteğe bağlıdır. Ancak API ile çalışan her entegrasyonda kullanmanızı öneriyoruz, çünkü üç işi birden görür:

  • Eşleştirme: Webhook ve API yanıtlarında order_id aynen geri gelir. Siparişinizi fatura kimliğiyle değil, kendi numaranızla bulursunuz.
  • İdempotentlik: Aynı order_id ile ikinci kez istek gönderdiğinizde yeni bir fatura açılmaz, mevcut fatura döner.
  • Sorgulama: GET /v1/invoices/by-order/{order_id} ile faturayı doğrudan sipariş numaranızla sorgulayabilirsiniz.

Webhook'lardan önce bu temeli sağlam kurmak, sonraki tüm adımları kolaylaştırır. Genel akışı kripto ödeme sistemi nedir yazımızda anlattık.

İdempotent fatura oluşturma nasıl çalışır?

Şu senaryoyu düşünün: Müşteri "Öde" butonuna basar, sunucunuz POST /v1/invoices isteğini gönderir, ama yanıt gelmeden bağlantı zaman aşımına uğrar. Fatura oluştu mu, oluşmadı mı? Bilmiyorsunuz.

order_id kullanıyorsanız cevap basittir: aynı isteği tekrar gönderin. Sonuç iki durumdan biridir:

Durum HTTP yanıtı Anlamı
Fatura daha önce oluşmamıştı 201 Created Yeni fatura açıldı
Aynı order_id ile fatura zaten var, parametreler aynı 200 OK Mevcut fatura döndü
Aynı order_id ile fatura var, parametreler farklı 409 · order_id_conflict İstek reddedildi

Aynı anda gelen iki istek bile (ör. müşterinin butona iki kez basması) tek faturaya çözülür. Böylece müşteriye asla iki farklı ödeme adresi gösterilmez.

409 order_id_conflict ne zaman gelir?

Aynı sipariş numarasıyla farklı tutar ya da farklı coin göndermeye çalışırsanız API bunu bir hata olarak kabul eder. Örneğin order-1001 için önce 25 USD, sonra 30 USD'lik fatura istediyseniz 409 order_id_conflict alırsınız. Bu bilinçli bir korumadır: aynı siparişin iki farklı tutarla ödenmesini engeller.

Sepet tutarı değiştiyse (müşteri ürün ekledi, kupon uyguladı) yeni bir sipariş numarası ya da sürüm eki kullanın: order-1001-v2 gibi.

Kod ile idempotent fatura

PHP kütüphanesiyle bir sipariş için fatura oluşturup ağ hatasında güvenle tekrar deneyen basit bir örnek:

<?php
require 'vendor/autoload.php';

use MercanPay\MercanPay;
use MercanPay\MercanPayException;

$zp = new MercanPay('https://mercanpay.com', getenv('MERCANPAY_API_KEY'));

function invoiceFor(MercanPay $zp, string $orderId, string $priceUsd): array
{
    for ($attempt = 1; $attempt <= 3; $attempt++) {
        try {
            return $zp->createUsdInvoice($priceUsd, ['order_id' => $orderId]);
        } catch (MercanPayException $e) {
            $retryable = $e->getHttpStatus() === 0 || $e->getHttpStatus() === 429 || $e->getHttpStatus() >= 500;
            if (!$retryable || $attempt === 3) {
                throw $e;
            }
            sleep($attempt * 2); // aynı order_id ile tekrar: çift fatura oluşmaz
        }
    }
}

getHttpStatus() değeri 0 ise istek hiç yanıt almamıştır (ağ hatası). 429 ve 5xx durumlarında da aynı istek güvenle tekrarlanabilir. 400 ya da 409 ise tekrar denemek işe yaramaz, isteği düzeltmeniz gerekir.

Python tarafında aynı mantık create_invoice(price_usd="25.00", order_id="order-1001") çağrısıyla kurulur. Ayrıntılar için Python ile kripto ödeme entegrasyonu rehberine bakabilirsiniz.

Sipariş numarası nasıl seçilmeli?

İyi bir order_id şu özellikleri taşır:

  • Benzersizdir: Mağazanızdaki her ödeme girişimi için tek. Veritabanınızdaki sipariş kimliği genellikle yeterlidir.
  • Tahmin edilemez olması şart değildir: order_id müşteriye gizli bir sır değildir, ama içine kişisel veri (e-posta, telefon) koymayın.
  • Sabittir: Aynı sipariş için her denemede aynı değeri üretir. Rastgele bir değeri her istekte yeniden oluşturursanız idempotentlik kaybolur.
  • Kısadır: 128 karakter sınırı var; order-1001 gibi okunabilir değerler destek yazışmalarında da işinizi kolaylaştırır.

Süresi dolan faturalar ve yeni deneme

Aynı order_id ile yapılan istek, mevcut fatura süresi dolmuş olsa bile o faturayı döndürür. Müşteri ödeme yapmadan süre dolduysa ve yeniden denemek istiyorsa yeni bir deneme numarası kullanın:

order-1001      → ilk fatura (expired)
order-1001-r2   → ikinci deneme

Kendi tarafınızda bir siparişe birden fazla fatura bağlanabileceğini modelleyin: orders tablosu ve ona bağlı payment_attempts gibi. Süre konusunu kripto fatura geçerlilik süresi yazımızda ayrıntılı ele aldık.

Webhook'ta eşleştirme

Ödeme kesinleştiğinde gelen webhook'ta data.invoice.order_id alanı sizin gönderdiğiniz değeri taşır. Siparişi bu alanla bulun, ardından üç kontrol yapın:

  1. İmzayı doğrulayın. Ayrıntılar webhook imzası doğrulama yazımızda.
  2. Coin ve tutarı karşılaştırın. token ve paid_amount beklediğiniz değerlerle uyumlu mu?
  3. Tekrarı eleyin. Aynı olay birden fazla gelebilir. Olay kimliğini (id) kaydedin ya da siparişi yalnızca paid değilse güncelleyin.
UPDATE orders
   SET status = 'paid', invoice_id = :invoice_id
 WHERE id = :order_id AND status <> 'paid';

Bu koşullu güncelleme, olay iki kez gelse bile siparişin bir kez işlenmesini sağlar. Yeniden deneme mantığını webhook yeniden deneme ve idempotent işleme yazımızda derinlemesine anlatıyoruz.

metadata ile ek bağlam

order_id tek bir değer taşır. Siparişe dair ek bilgilere ihtiyacınız varsa metadata alanını kullanın. En fazla 4 KB'lık bir JSON nesnesidir, müşteriye gösterilmez ve webhook'larla API yanıtlarında aynen geri döner:

$zp->createUsdInvoice('49.90', [
    'order_id' => 'order-1001',
    'metadata' => ['customer_id' => 42, 'plan' => 'pro'],
]);

Ancak siparişin doğruluğu için metadata'ya değil, kendi veritabanınıza güvenin. Metadata bir kolaylıktır, tek doğruluk kaynağı değildir.

Mutabakat: kayıtlar birbirini tutuyor mu?

Eşleştirmenin son adımı düzenli mutabakattır. Webhook'lardan biri sunucunuz kapalıyken kaçtıysa bile API ile açığı kapatabilirsiniz:

$page = $zp->listInvoices('paid', 20);
foreach ($page['data'] as $invoice) {
    // $invoice['order_id'] sizde "paid" değilse işaretleyin
}
// sonraki sayfa: $zp->listInvoices('paid', 20, $page['next_before']);

Tek bir siparişi kontrol etmek için getInvoiceByOrder('order-1001') yeterlidir. Günlük ya da saatlik küçük bir iş, "ödendi ama siparişi açılmadı" türü destek taleplerinin önüne geçer. Panelden toplu kontrol için ödeme raporlarını CSV, Excel ve PDF olarak indirebilirsiniz; dışa aktarılan faturalarda "Sipariş No" sütunu da bulunur.

Sık yapılan hatalar

  • order_id göndermemek: Yeniden denemede çift fatura oluşur, müşteri iki farklı link görebilir.
  • Her istekte yeni rastgele değer üretmek: İdempotentlik korumasını fiilen kapatır.
  • Tutar değiştiğinde aynı order_id'yi kullanmak: 409 order_id_conflict alırsınız.
  • Siparişi tarayıcı yönlendirmesiyle kapatmak: success_url parametreleri taklit edilebilir. Sipariş yalnızca doğrulanmış webhook ya da API sorgusuyla onaylanmalıdır.
  • Tek bir faturaya birden fazla sipariş bağlamak: Her sipariş için ayrı fatura açın; eşleştirme ancak böyle net kalır.

Sık sorulan sorular

order_id zorunlu mu?

Hayır, isteğe bağlıdır. Panelden tek tek fatura oluşturuyorsanız boş bırakabilirsiniz. API entegrasyonunda ise çift faturayı önlemek için kullanmanızı öneriyoruz.

İki farklı mağazamda aynı sipariş numaraları var, sorun olur mu?

order_id eşsizliği satıcı hesabı içinde geçerlidir. Aynı hesapta iki mağaza çalıştırıyorsanız numaralara bir önek ekleyin: shopA-1001, shopB-1001.

Fatura kimliğini mi saklamalıyım, order_id'yi mi?

İkisini de saklayın. Fatura kimliği (id) destek taleplerinde ve API sorgularında işinize yarar; order_id ise kendi sisteminizle bağlantıyı kurar.

Aynı order_id ile gelen yanıtın yeni mi eski mi olduğunu nasıl anlarım?

HTTP durum koduna bakın: 201 yeni bir fatura açıldığını, 200 mevcut faturanın döndüğünü gösterir.

MercanPay ile başlayın

Güvenilir bir fatura sipariş eşleştirmesi, sorunsuz bir kripto ödeme deneyiminin temelidir. Satıcı başvurunuzu yapın, tüm alanlar için dokümantasyonu inceleyin ve ilk entegrasyonunuzu idempotent biçimde kurun.

#API#order_id#Entegrasyon#Webhook

İlgili yazılar

Kripto ödemeleri dakikalar içinde almaya başlayın

USDT ve TRX (TRC20) ile ödeme alın. %0,4'ten başlayan komisyon, hazır ödeme sayfası, API ve webhook.