Esc
Start typing to search...

Payment Modifications

Payment Modifications Overview #

You can cancel or refund payments made in the marketplace system. On this page, you will learn about the following operations:

  • PaymentRefund - Partial or full refund operations
  • PaymentCancel - Payment cancellation (same day only)

Cancel vs Refund #

OperationWhen?Description
CancelSame dayPayment is cancelled on the same day, customer is not charged
RefundNext day and afterThe charged amount is refunded to the customer, takes 2-10 business days

1. PaymentRefund #

Fully or partially refunds a completed payment.

Endpoint #

TEST:

POST https://apitest.paynkolay.com.tr/marketplace/v1/payment/refund

PROD:

POST https://api.paynkolay.com.tr/marketplace/v1/payment/refund

Request Parameters #

{
  "apiKey": "calculated_api_key_for_refund",
  "apiSecretKey": "sx_iptal_value",
  "mpCode": "MP12345",
  "refCode": "REF123456789",
  "trxType": "refund",
  "trxDate": "2025-01-20",
  "totalTrxAmount": 150.00,
  "trxCurrency": "TRY",
  "sellerList": [
    {
      "sellerExternalId": "SELLER_001",
      "trxAmount": 100.00,
      "refundedCommissionAmount": 5.00,
      "withholdingTax": 0.80
    },
    {
      "sellerExternalId": "SELLER_002",
      "trxAmount": 50.00,
      "refundedCommissionAmount": 2.50,
      "withholdingTax": 0.40
    }
  ]
}

Parameter Details #

ParameterTypeRequiredDescription
apiKeyStringCalculated API key for cancellation/refund
apiSecretKeyStringSpecial SX value for cancellation operations
mpCodeStringMarketplace code
refCodeStringReference code of the original transaction
trxTypeStringTransaction type: refund
trxDateStringTransaction date (in yyyy-MM-dd format)
totalTrxAmountBigDecimalTotal refund amount
trxCurrencyStringCurrency (TRY, USD, EUR)

Seller List (sellerList) #

ParameterTypeRequiredDescription
sellerExternalIdStringSeller's external ID
trxAmountBigDecimalAmount to be refunded
refundedCommissionAmountBigDecimalCommission amount to be refunded
withholdingTaxBigDecimalWithholding tax amount to be refunded
Refund Amount: 100 TL Excluding VAT: 80 TL Refund Withholding Tax: 80 TL × 0.01 = 0.8 TL d-flex align-items-start mb-4" role="alert">
warning

Refund with Discount Parameters #

Things to consider when refunding discounted transactions:

Refund with Seller Discount #

{
  "totalTrxAmount": 900.00,
  "sellerList": [
    {
      "sellerExternalId": "SELLER_001",
      "trxAmount": 1000.00,
      "sellerDiscountAmount": 100.00,
      "withholdingTax": 7.20
    }
  ]
}
Product Amount: 1000 TL
Seller Discount: 100 TL
Charged Amount (trxAmount - sellerDiscountAmount): 900 TL
totalTrxAmount: 900 TL

Refund with Marketplace Discount #

{
  "totalTrxAmount": 900.00,
  "mpDiscountAmount": 100.00,
  "sellerList": [
    {
      "sellerExternalId": "SELLER_001",
      "trxAmount": 1000.00,
      "sellerDiscountAmount": 0.00
    }
  ]
}
Product Amount: 1000 TL
Marketplace Discount: 100 TL
totalTrxAmount = trxAmount - mpDiscountAmount = 900 TL

Response #

{
  "data": {
    "trxStatus": "APPROVED",
    "mpReferenceCode": "MPREF987654",
    "trxType": "REFUND",
    "trxReferenceCode": "REFUND123456"
  },
  "success": true,
  "responseCode": "200",
  "responseMessage": "SUCCESS"
}

Partial Refund Example #

// Orijinal ödeme: 500 TL (3 satıcı)
// Sadece 1 satıcıya iade yapılacak / Only 1 seller will be refunded

async function partialRefund() {
  const refund = await paymentRefund({
    apiKey: calculateRefundApiKey(),
    apiSecretKey: process.env.API_SECRET_KEY_CANCEL,
    mpCode: 'MP12345',
    refCode: 'REF_ORIGINAL',
    trxType: 'refund',
    trxDate: '2025-01-20',
    totalTrxAmount: 150.00,  // Sadece 1 satıcının tutarı / Only 1 seller's amount
    trxCurrency: 'TRY',
    sellerList: [
      {
        sellerExternalId: 'SELLER_001',
        trxAmount: 150.00,
        refundedCommissionAmount: 7.50,
        withholdingTax: 1.20
      }
      // Diğer satıcılar gönderilmez / Other sellers are not sent
    ]
  });

  return refund;
}

2. PaymentCancel #

Cancels payments made on the same day.

Endpoint #

TEST:

POST https://apitest.paynkolay.com.tr/marketplace/v1/payment/cancel

PROD:

POST https://api.paynkolay.com.tr/marketplace/v1/payment/cancel

Request Parameters #

{
  "apiKey": "calculated_api_key_for_cancel",
  "apiSecretKey": "sx_iptal_value",
  "mpCode": "MP12345",
  "refCode": "REF123456789",
  "trxType": "cancel",
  "trxDate": "2025-01-20",
  "totalTrxAmount": 150.00,
  "trxCurrency": "TRY",
  "sellerList": []
}
ParameterTypeRequiredDescription
apiKeyStringCalculated API key for cancellation
apiSecretKeyStringSpecial SX value for cancellation operations
mpCodeStringMarketplace code
refCodeStringReference code of the transaction to be cancelled
trxTypeStringTransaction type: cancel
trxDateStringTransaction date (in yyyy-MM-dd format)
totalTrxAmountBigDecimalTotal amount to be cancelled
trxCurrencyStringCurrency
sellerListArraySent as empty array []

Response #

{
  "data": {
    "trxStatus": "APPROVED",
    "mpReferenceCode": "MPCANCEL987654",
    "trxType": "CANCEL",
    "trxReferenceCode": "CANCEL123456"
  },
  "success": true,
  "responseCode": "200",
  "responseMessage": "SUCCESS"
}

Cancel/Refund Hash Calculation #

A special SX value is used for cancellation and refund operations, and the hash calculation is as follows:

const crypto = require('crypto');

function calculateRefundCancelApiKey(apiSecretKey_iptal, merchantSecretKey, trxType, trxDate, amount, trxCurrency, referenceCode) {
  // String birleştirme
  const hashString = apiSecretKey_iptal + '|' + merchantSecretKey + '|' + trxType + '|' + trxDate + '|' + amount + '|' + trxCurrency + '|' + referenceCode;

  // SHA512 hash
  const hash = crypto.createHash('sha512').update(hashString, 'utf8').digest();

  // Base64 encode
  return hash.toString('base64');
}

// Kullanım
const apiSecretKey_iptal = process.env.API_SECRET_KEY_CANCEL; // İptal için özel SX
const merchantSecretKey = process.env.MERCHANT_SECRET_KEY;

const apiKey = calculateRefundCancelApiKey(apiSecretKey_iptal, merchantSecretKey, 'refund', '2025-01-20', 100.00, 'TRY', 'REF123');

Full Refund Example #

class PaymentRefundManager {
  constructor(apiSecretKey, apiSecretKey_cancel, merchantSecretKey, mpCode) {
    this.apiSecretKey = apiSecretKey;
    this.apiSecretKey_cancel = apiSecretKey_cancel;
    this.merchantSecretKey = merchantSecretKey;
    this.mpCode = mpCode;
  }

  calculateRefundApiKey(trxType, trxDate, amount, trxCurrency, referenceCode) {
    const hashString = this.apiSecretKey_cancel + '|' + this.merchantSecretKey + '|' + trxType + '|' + trxDate + '|' + amount + '|' + trxCurrency + '|' + referenceCode;
    const hash = crypto.createHash('sha512').update(hashString, 'utf8').digest();
    return hash.toString('base64');
  }

  async refundPayment(refCode, sellers) {
    // Toplam tutarı hesapla
    const totalAmount = sellers.reduce((sum, seller) => {
      return sum + (seller.trxAmount - (seller.sellerDiscountAmount || 0));
    }, 0);

    // Stopaj hesapla
    const sellersWithTax = sellers.map(seller => ({
      ...seller,
      withholdingTax: this.calculateWithholdingTax(
        seller.trxAmountWithoutVAT || seller.trxAmount * 0.8
      )
    }));

    const trxType = 'refund';
    const trxDate = new Date().toISOString().split('T')[0];
    const trxCurrency = 'TRY';
    const apiKey = this.calculateRefundApiKey(trxType, trxDate, totalAmount, trxCurrency, refCode);

    const response = await axios.post(
      'https://apitest.paynkolay.com.tr/marketplace/v1/payment/refund',
      {
        apiKey,
        apiSecretKey: this.apiSecretKey_cancel,
        mpCode: this.mpCode,
        refCode,
        trxType,
        trxDate,
        totalTrxAmount: totalAmount,
        trxCurrency,
        sellerList: sellersWithTax
      }
    );

    return response.data;
  }

  calculateWithholdingTax(amountWithoutVAT) {
    return amountWithoutVAT * 0.01; // %1 stopaj
  }

  async cancelPayment(refCode, totalAmount) {
    const trxType = 'cancel';
    const trxDate = new Date().toISOString().split('T')[0];
    const trxCurrency = 'TRY';
    const apiKey = this.calculateRefundApiKey(trxType, trxDate, totalAmount, trxCurrency, refCode);

    const response = await axios.post(
      'https://apitest.paynkolay.com.tr/marketplace/v1/payment/cancel',
      {
        apiKey,
        apiSecretKey: this.apiSecretKey_cancel,
        mpCode: this.mpCode,
        refCode,
        trxType,
        trxDate,
        totalTrxAmount: totalAmount,
        trxCurrency,
        sellerList: []
      }
    );

    return response.data;
  }

  async cancelOrRefund(refCode, paymentDate, totalAmount, sellers = null) {
    const today = new Date().toISOString().split('T')[0];
    const paymentDay = new Date(paymentDate).toISOString().split('T')[0];

    // Aynı gün ise cancel, değilse refund
    if (paymentDay === today) {
      return await this.cancelPayment(refCode, totalAmount);
    } else {
      if (!sellers) {
        throw new Error('Refund için satıcı bilgileri gerekli');
      }
      return await this.refundPayment(refCode, sellers);
    }
  }
}

// Kullanım
const manager = new PaymentRefundManager(
  process.env.API_SECRET_KEY,
  process.env.API_SECRET_KEY_CANCEL,
  process.env.MERCHANT_SECRET_KEY,
  'MP12345'
);

// Otomatik cancel veya refund
const result = await manager.cancelOrRefund(
  'REF123456789',
  '2025-01-20',
  150.00,
  [
    {
      sellerExternalId: 'SELLER_001',
      trxAmount: 100.00,
      refundedCommissionAmount: 5.00
    },
    {
      sellerExternalId: 'SELLER_002',
      trxAmount: 50.00,
      refundedCommissionAmount: 2.50
    }
  ]
);

Partial Refund Scenarios #

Scenario 1: Single Product Refund (Multiple Sellers) #

// Orijinal sipariş: 3 satıcı, toplam 500 TL
// Sadece SELLER_002'nin ürünü iade edilecek

await refundPayment('REF123', [
  {
    sellerExternalId: 'SELLER_002',
    trxAmount: 150.00,
    refundedCommissionAmount: 7.50,
    withholdingTax: 1.20
  }
]);
// SELLER_001 ve SELLER_003 iade edilmedi

Scenario 2: Partial Amount Refund #

// Satıcı indirim yapmak istiyor
// Orijinal: 200 TL, İade: 50 TL

await refundPayment('REF456', [
  {
    sellerExternalId: 'SELLER_001',
    trxAmount: 50.00,  // Sadece 50 TL iade
    refundedCommissionAmount: 2.50,
    withholdingTax: 0.40
  }
]);

Scenario 3: Damaged Product Discount #

// Ürün hasarlı geldi, %30 indirim yapılacak
// Orijinal: 300 TL

await refundPayment('REF789', [
  {
    sellerExternalId: 'SELLER_001',
    trxAmount: 90.00,  // 300 * 0.30 = 90 TL iade
    refundedCommissionAmount: 4.50,
    withholdingTax: 0.72
  }
]);

Error Situations #

Cancel/Refund May Fail Because: #

ErrorReasonSolution
ALREADY_REFUNDEDTransaction already refundedCheck refund status
INSUFFICIENT_BALANCEInsufficient balanceSeller account must have sufficient balance
INVALID_DATEInvalid dateCheck date format (yyyy-MM-dd)
TRANSACTION_NOT_FOUNDTransaction not foundCheck refCode
SAME_DAY_USE_CANCELRefund used for same dayUse Cancel
INVALID_HASHHash validation errorCheck cancellation SX value

Error Handling Example #

async function safeRefund(refCode, sellers) {
  try {
    const result = await refundPayment(refCode, sellers);

    if (result.success) {
      console.log('İade başarılı:', result.data.trxReferenceCode);
      return result;
    } else {
      throw new Error(result.responseMessage);
    }

  } catch (error) {
    console.error('İade hatası:', error.message);

    // Hata tipine göre işlem
    if (error.message.includes('ALREADY_REFUNDED')) {
      console.log('Bu işlem zaten iade edilmiş');
      // Veritabanında güncelle
    } else if (error.message.includes('INSUFFICIENT_BALANCE')) {
      console.log('Yetersiz bakiye, sonra tekrar dene');
      // Kuyruğa ekle
    } else {
      // Genel hata
      console.log('İade başarısız, destek ekibine bildir');
    }

    throw error;
  }
}

Cancel/Refund Notification #

async function processRefundWithNotification(refCode, sellers, customerEmail) {
  try {
    // 1. İade işlemini gerçekleştir
    const result = await refundPayment(refCode, sellers);

    // 2. Müşteriye bildirim gönder
    await sendEmail(customerEmail, {
      subject: 'İade İşleminiz Başlatıldı',
      body: `
        Merhaba,

        ${refCode} numaralı siparişiniz için iade işlemi başlatılmıştır.

        İade Tutarı: ${result.data.totalAmount} TL
        İade Referans: ${result.data.trxReferenceCode}

        İade tutarı 2-10 iş günü içinde hesabınıza geçecektir.

        İyi günler dileriz.
      `
    });

    // 3. Satıcılara bildir
    for (const seller of sellers) {
      await notifySeller(seller.sellerExternalId, {
        refCode,
        amount: seller.trxAmount,
        commission: seller.refundedCommissionAmount
      });
    }

    return result;

  } catch (error) {
    // Hata durumunda da müşteriyi bilgilendir
    await sendEmail(customerEmail, {
      subject: 'İade İşlemi Başarısız',
      body: 'İade işleminizde bir sorun oluştu. Lütfen müşteri hizmetleriyle iletişime geçin.'
    });

    throw error;
  }
}

Next Steps #

After learning about cancellation and refund operations: