Chargeback Help

Transaction Matching

Implement a Currency Exchanger to USD, amounts are converted to USD when Request currency is different from Payment currency.

    use MerchantOP\Services\ExchangerContract;
    
    class Exchanger implements ExchangerContract
    {
        protected $rates = [
            'EUR' => 1.21,
            'GBP' => 1.37,
        ];
    
        public function __construct()
        {
            $this->rates = $this->getFreshRates();
        }
    
        public function exchangeToUSD($currency, $amount)
        {
            return $this->rates[$currency] * $amount;
        }
    
        protected function getFreshRates()
        {
            //
        }
    }

Capture request parameters:

    use MerchantOP\Models\ProvisionRequest;
    
    $request = ProvisionRequest::capture();

Preliminary filter available transactions by card number and transaction date:

    $transactionDate = $request->authorizationDate ?: $request->settlementDate;
    
    $transactions = Transactions::where('card_bin', $request->cardBin)
        ->where('card_last4', $request->cardLast4)
        ->where('transaction_timestamp', '>=', $request->authorizationDate->add(DateInterval::createFromDateString('-3 days')))
        ->where('transaction_timestamp', '<=', $request->authorizationDate->add(DateInterval::createFromDateString('+3 days')));

Transform raw filtered entities to Payment objects:

    $payments = $transactions->map(function ($transactions) {
        $payment = new Payment;
        $payment->authDate = $transaction->transaction_timestamp;
        $payment->cardBin = $transaction->card_bin;
        $payment->cardLast4 = $transaction->card_last4;
        $payment->total = $transaction->amount;
        $payment->currency = $transaction->currency;
        $payment->authDescriptor = $transaction->descriptor;
        $payment->arn = $transaction->arn;
        $payment->orderId = $transaction->order_id;
        
        return $payment;
    });

Match Payments to requested parameters:

    use MerchantOP\OrderPullingManager;
    
    $matched = OrderPullingManager::matcher(new Exchanger)->match($payments, $request);

Matching steps (the process stops on the step where only a single payment is matched):

  1. Exact Match by ARN, Order ID, Gateway ID, if both available in Request and Payment.
  2. Match by Card Number, Transaction Date (+- 2 days), Amount (exchanged to USD; on exchange, a difference of 5 USD is accepted)
  3. Match by Descriptor (65% similarity; removed numbers, whitespaces)
  4. Match by exact payment date

Check matched payments:

    if (!$matched) {
        abort(404); # Not found
    } elseif ($matched === true) {
        abort(300); # Multiple choices
    } else {
        $response = new ProvisionResponse;
        $response->payments[] = $matched;
        // build response...
        
        echo $response->toJson();
    }

© 2025 Chargeback Help. All rights reserved.