ข้ามไปยังเนื้อหาหลัก

รหัสคำแนะนำสำหรับร้านค้า

ทำความเข้าใจว่าทำไมธุรกรรมถูกปฏิเสธ และกำหนดขั้นตอนถัดไปที่เหมาะสมโดยใช้รหัสคำแนะนำสำหรับร้านค้าในการตอบกลับการเรียกเก็บเงิน

ภาพรวม

เมื่อธุรกรรมบัตรถูกปฏิเสธ Omise จะส่งค่า merchant_advice ในการตอบกลับการเรียกเก็บเงิน ฟิลด์นี้ประกอบด้วยข้อความมาตรฐานที่ช่วยให้คุณเข้าใจว่าทำไมธุรกรรมล้มเหลว และควรดำเนินการอย่างไรต่อไป

ประโยชน์หลัก:

  • ข้อความที่สอดคล้องกัน - คำแนะนำเดียวกันไม่ว่าจะเป็นเครือข่ายบัตรใด (Visa, Mastercard เป็นต้น)
  • คำแนะนำที่ปฏิบัติได้ - ขั้นตอนถัดไปที่ชัดเจนสำหรับการปฏิเสธแต่ละประเภท
  • ประสบการณ์ลูกค้าที่ดีขึ้น - ข้อความแสดงข้อผิดพลาดที่ดีกว่าสำหรับผู้ถือบัตร
  • ลดการปฏิเสธที่ไม่จำเป็น - รู้ว่าเมื่อใดควรลองใหม่ และเมื่อใดควรขอวิธีการชำระเงินใหม่

ทำความเข้าใจการตอบกลับ

เมื่อการเรียกเก็บเงินถูกปฏิเสธ การตอบกลับจะประกอบด้วย:

{
"object": "charge",
"id": "chrg_test_xxx",
"status": "failed",
"failure_code": "insufficient_fund",
"failure_message": "insufficient fund",
"merchant_advice": "Cardholder should contact their bank or use a different payment method.",
"merchant_advice_code": 3,
"card": {
"brand": "Visa",
"last_digits": "4242"
}
}
ฟิลด์คำอธิบาย
failure_codeรหัสข้อผิดพลาดทางเทคนิค
failure_messageคำอธิบายข้อผิดพลาดโดยย่อ
merchant_adviceคำแนะนำที่อ่านง่ายสำหรับร้านค้า
merchant_advice_codeรหัสตัวเลขสำหรับการจัดการโดยโปรแกรม

รหัสคำแนะนำสำหรับร้านค้า

รหัสทั่วไปและการดำเนินการ

รหัสคำแนะนำคำอธิบายการดำเนินการที่แนะนำ
1ไม่ต้องลองใหม่ธุรกรรมจะไม่สำเร็จขอวิธีการชำระเงินอื่น
2ลองใหม่ภายหลังปัญหาชั่วคราวลองใหม่หลังจากรอสักครู่ (หลายชั่วโมง/วันถัดไป)
3ติดต่อผู้ออกบัตรผู้ถือบัตรต้องแก้ไขกับธนาคารขอให้ลูกค้าติดต่อธนาคาร
4ขอบัตรใหม่บัตรไม่ถูกต้อง/หมดอายุขอบัตรอื่น
5ลองใหม่ด้วย 3DSต้องการการยืนยันตัวตนลองใหม่โดยเปิดใช้งาน 3D Secure
6ข้อผิดพลาดทางเทคนิคปัญหาระบบ/เครือข่ายลองใหม่ทันทีหรือหลังจากรอสักครู่

ข้อมูลอ้างอิงรหัสโดยละเอียด

รหัส 1: ไม่ต้องลองใหม่

ธุรกรรมไม่สามารถสำเร็จได้ด้วยบัตรนี้ อย่าพยายามลองใหม่

สาเหตุทั่วไป:

  • บัตรถูกแจ้งว่าสูญหาย/ถูกขโมย
  • บัญชีถูกปิด
  • ตรวจพบกิจกรรมฉ้อโกง
  • บัตรถูกบล็อกถาวร

การดำเนินการ: ขอวิธีการชำระเงินอื่นจากลูกค้า

if (charge.merchant_advice_code === 1) {
// ลบบัตรนี้ออกจากวิธีการชำระเงินที่บันทึกไว้
await removePaymentMethod(customer.id, card.id);

// แจ้งลูกค้า
await sendNotification(customer, {
message: 'Your card could not be charged. Please add a new payment method.'
});
}

รหัส 2: ลองใหม่ภายหลัง

การปฏิเสธเป็นการชั่วคราว ธุรกรรมอาจสำเร็จหากลองใหม่ในภายหลัง

สาเหตุทั่วไป:

  • ยอดเงินไม่เพียงพอ (ชั่วคราว)
  • เกินวงเงินรายวัน/รายสัปดาห์
  • ระบบผู้ออกบัตรกำลังบำรุงรักษา
  • ปริมาณธุรกรรมสูง

การดำเนินการ: รอและลองใหม่ (โดยทั่วไปหลังจาก 24 ชั่วโมง)

if (charge.merchant_advice_code === 2) {
// ตั้งเวลาลองใหม่ในวันพรุ่งนี้
await schedulePaymentRetry({
charge_id: charge.id,
retry_at: addHours(new Date(), 24),
max_retries: 3
});
}

รหัส 3: ติดต่อผู้ออกบัตร

ผู้ถือบัตรต้องติดต่อธนาคารเพื่อแก้ไขปัญหา

สาเหตุทั่วไป:

  • บัญชีถูกระงับเพื่อความปลอดภัย
  • ตรวจพบกิจกรรมผิดปกติ
  • ต้องการการยืนยัน
  • ต้องแจ้งการเดินทาง

การดำเนินการ: แจ้งลูกค้าให้ติดต่อผู้ออกบัตร

if (charge.merchant_advice_code === 3) {
await sendNotification(customer, {
message: 'Your payment was declined. Please contact your bank to resolve this issue, then try again.'
});
}

รหัส 4: ขอบัตรใหม่

บัตรไม่ถูกต้องและไม่สามารถใช้งานได้

สาเหตุทั่วไป:

  • บัตรหมดอายุ
  • หมายเลขบัตรไม่ถูกต้อง
  • บัตรยังไม่ได้เปิดใช้งาน
  • บัตรถูกยกเลิก

การดำเนินการ: ขอให้ลูกค้าใช้บัตรอื่น

if (charge.merchant_advice_code === 4) {
await sendNotification(customer, {
message: 'This card is no longer valid. Please update your payment method.'
});
}

รหัส 5: ลองใหม่ด้วย 3D Secure

ผู้ออกบัตรต้องการการยืนยันตัวตนเพิ่มเติม

สาเหตุทั่วไป:

  • ต้องการ SCA (บัตรยุโรป)
  • นโยบายผู้ออกบัตรต้องการ 3DS
  • ธุรกรรมมูลค่าสูง
  • ธุรกรรมครั้งแรก

การดำเนินการ: ลองธุรกรรมใหม่โดยเปิดใช้งาน 3D Secure

if (charge.merchant_advice_code === 5) {
// ลองใหม่ด้วย 3DS
const charge = await omise.charges.create({
amount: originalAmount,
currency: 'thb',
card: card.id,
return_uri: 'https://yoursite.com/3ds-complete',
// 3DS จะถูกเรียกใช้โดยอัตโนมัติ
});

// เปลี่ยนเส้นทางไปยังการยืนยันตัวตน 3DS
if (charge.authorize_uri) {
redirect(charge.authorize_uri);
}
}

รหัส 6: ข้อผิดพลาดทางเทคนิค

เกิดข้อผิดพลาดของระบบหรือเครือข่าย

สาเหตุทั่วไป:

  • หมดเวลาเครือข่าย
  • ระบบผู้ออกบัตรไม่พร้อมใช้งาน
  • ข้อผิดพลาดในการประมวลผล
  • ปัญหาการเชื่อมต่อเกตเวย์

การดำเนินการ: ลองใหม่ทันทีหรือหลังจากรอสักครู่

if (charge.merchant_advice_code === 6) {
// ลองใหม่ทันที
const retryCharge = await omise.charges.create({
amount: charge.amount,
currency: charge.currency,
card: charge.card.id
});
}

ตัวอย่างการใช้งาน

ระบบลองชำระเงินใหม่

const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});

async function processPayment(customerId, amount, cardId) {
try {
const charge = await omise.charges.create({
amount: amount,
currency: 'thb',
card: cardId,
metadata: {
customer_id: customerId,
attempt: 1
}
});

if (charge.status === 'successful') {
return { success: true, charge };
}

// จัดการธุรกรรมที่ถูกปฏิเสธ
return handleDecline(charge, customerId);

} catch (error) {
return { success: false, error: error.message };
}
}

async function handleDecline(charge, customerId) {
const code = charge.merchant_advice_code;

switch (code) {
case 1: // ไม่ต้องลองใหม่
await notifyCustomer(customerId, 'payment_failed_permanent', {
message: charge.merchant_advice
});
await flagCardForRemoval(charge.card.id);
return {
success: false,
action: 'request_new_payment_method',
message: charge.merchant_advice
};

case 2: // ลองใหม่ภายหลัง
await scheduleRetry(charge, customerId, { delay: '24h' });
return {
success: false,
action: 'retry_scheduled',
retry_at: getNextRetryTime()
};

case 3: // ติดต่อผู้ออกบัตร
await notifyCustomer(customerId, 'contact_bank', {
message: charge.merchant_advice
});
return {
success: false,
action: 'contact_issuer',
message: 'Please contact your bank to resolve this issue.'
};

case 4: // ขอบัตรใหม่
await notifyCustomer(customerId, 'update_card', {
message: charge.merchant_advice
});
return {
success: false,
action: 'update_payment_method',
message: 'This card is no longer valid. Please add a new card.'
};

case 5: // ลองใหม่ด้วย 3DS
const retryCharge = await omise.charges.create({
amount: charge.amount,
currency: charge.currency,
card: charge.card.id,
return_uri: `https://example.com/3ds-callback/${charge.id}`
});

if (retryCharge.authorize_uri) {
return {
success: false,
action: 'redirect_3ds',
authorize_uri: retryCharge.authorize_uri
};
}
break;

case 6: // ข้อผิดพลาดทางเทคนิค
// ลองใหม่ทันที
const immediateRetry = await omise.charges.create({
amount: charge.amount,
currency: charge.currency,
card: charge.card.id
});

if (immediateRetry.status === 'successful') {
return { success: true, charge: immediateRetry };
}

// ตั้งเวลาลองใหม่ในภายหลัง
await scheduleRetry(charge, customerId, { delay: '1h' });
return {
success: false,
action: 'retry_scheduled',
message: 'Temporary issue. We will retry shortly.'
};

default:
return {
success: false,
action: 'unknown',
message: charge.merchant_advice || 'Payment failed. Please try again.'
};
}
}

// การลองใหม่อัจฉริยะด้วย exponential backoff
async function scheduleRetry(charge, customerId, options) {
const attempt = (charge.metadata?.attempt || 1) + 1;
const maxAttempts = 4;

if (attempt > maxAttempts) {
await notifyCustomer(customerId, 'payment_failed_final', {
message: 'We were unable to process your payment after multiple attempts.'
});
return;
}

// Exponential backoff: 1 ชม., 4 ชม., 12 ชม.
const delays = ['1h', '4h', '12h'];
const delay = delays[Math.min(attempt - 2, delays.length - 1)];

await retryQueue.add({
charge_id: charge.id,
customer_id: customerId,
amount: charge.amount,
currency: charge.currency,
card_id: charge.card.id,
attempt: attempt
}, {
delay: parseDelay(delay)
});
}

ข้อความแสดงข้อผิดพลาดสำหรับลูกค้า

const customerMessages = {
1: 'ไม่สามารถใช้วิธีการชำระเงินนี้ได้ กรุณาลองใช้บัตรอื่น',
2: 'การชำระเงินไม่พร้อมใช้งานชั่วคราว เราจะลองใหม่เร็วๆ นี้',
3: 'กรุณาติดต่อธนาคารของคุณเพื่ออนุญาตการชำระเงินนี้',
4: 'บัตรนี้หมดอายุหรือไม่ถูกต้อง กรุณาใช้บัตรอื่น',
5: 'ต้องการการยืนยันเพิ่มเติม คุณจะถูกเปลี่ยนเส้นทางไปยังธนาคาร',
6: 'เกิดปัญหาทางเทคนิค กรุณาลองใหม่อีกครั้ง'
};

function getCustomerMessage(merchantAdviceCode, defaultMessage) {
return customerMessages[merchantAdviceCode] || defaultMessage || 'การชำระเงินล้มเหลว กรุณาลองใหม่อีกครั้ง';
}

การทดสอบ

ใช้บัตรทดสอบเฉพาะเพื่อจำลองรหัสคำแนะนำสำหรับร้านค้าต่างๆ:

บัตรทดสอบ: 4111 1111 1117 0018

ตัวเลขสองหลักสุดท้ายของจำนวนเงินที่เรียกเก็บกำหนดรหัสคำแนะนำ:

จำนวนเงิน (บาท)รหัสคำแนะนำสถานการณ์
100011ไม่ต้องลองใหม่
100022ลองใหม่ภายหลัง
100033ติดต่อผู้ออกบัตร
100044ขอบัตรใหม่
100055ลองใหม่ด้วย 3DS
100066ข้อผิดพลาดทางเทคนิค

ตัวอย่างการทดสอบ

# ทดสอบการตอบกลับ "ไม่ต้องลองใหม่"
curl https://api.omise.co/charges \
-u skey_test_YOUR_KEY: \
-d "amount=10001" \
-d "currency=thb" \
-d "card=tokn_test_xxx"

# ทดสอบการตอบกลับ "ลองใหม่ด้วย 3DS"
curl https://api.omise.co/charges \
-u skey_test_YOUR_KEY: \
-d "amount=10005" \
-d "currency=thb" \
-d "card=tokn_test_xxx"

แนวทางปฏิบัติที่ดี

1. ตรวจสอบคำแนะนำร้านค้าเสมอ

if (charge.status === 'failed') {
// ตรวจสอบ merchant_advice_code เสมอเพื่อดำเนินการอย่างเหมาะสม
const action = determineAction(charge.merchant_advice_code);
handleDeclinedPayment(charge, action);
}

2. ใช้ตรรกะการลองใหม่อย่างชาญฉลาด

  • รหัส 1: ไม่ลองใหม่เด็ดขาด
  • รหัส 2: ลองใหม่หลังจาก 24 ชั่วโมง สูงสุด 3 ครั้ง
  • รหัส 3-4: รอการดำเนินการจากลูกค้า
  • รหัส 5: ลองใหม่ทันทีด้วย 3DS
  • รหัส 6: ลองใหม่ทันที จากนั้นเพิ่มระยะเวลารอ

3. บันทึกข้อมูลสำหรับการวิเคราะห์

await analytics.track('payment_declined', {
charge_id: charge.id,
failure_code: charge.failure_code,
merchant_advice_code: charge.merchant_advice_code,
card_brand: charge.card.brand,
amount: charge.amount
});

4. สื่อสารอย่างชัดเจน

แปลงรหัสทางเทคนิคเป็นข้อความที่เป็นมิตรกับลูกค้าเพื่อช่วยให้พวกเขาแก้ไขปัญหาได้

คำถามที่พบบ่อย

จะทำอย่างไรถ้าไม่มี merchant_advice_code?

การปฏิเสธบางรายการที่เก่ากว่าหรือวิธีการชำระเงินที่ไม่ใช่บัตรอาจไม่มีรหัสคำแนะนำสำหรับร้านค้า ในกรณีเหล่านี้ ให้ใช้ฟิลด์ failure_code และ failure_message เป็นแนวทางแทน

ควรแสดง merchant_advice ให้ลูกค้าเห็นหรือไม่?

ฟิลด์ merchant_advice มีไว้สำหรับร้านค้า ไม่ใช่ลูกค้า ควรสร้างข้อความที่เป็นมิตรกับลูกค้าตามรหัสคำแนะนำแทนที่จะแสดงข้อความดิบ

ควรลองชำระเงินที่ถูกปฏิเสธใหม่บ่อยแค่ไหน?

สำหรับรหัส 2 (ลองใหม่ภายหลัง) เราแนะนำ:

  • ลองใหม่ครั้งแรก: หลังจาก 24 ชั่วโมง
  • ลองใหม่ครั้งที่สอง: หลังจาก 3 วัน
  • ลองใหม่ครั้งที่สาม: หลังจาก 7 วัน
  • จากนั้นแจ้งลูกค้าให้อัปเดตวิธีการชำระเงิน
รหัสคำแนะนำร้านค้าเหมือนกันในทุกเครือข่ายบัตรหรือไม่?

ใช่ Omise ทำให้คำแนะนำเป็นมาตรฐานเดียวกันทั้ง Visa, Mastercard และเครือข่ายบัตรอื่นๆ เพื่อให้คุณได้รับรหัสที่สอดคล้องกันไม่ว่าจะเป็นแบรนด์บัตรใด

จะหารายการรหัสทั้งหมดได้ที่ไหน?

ดาวน์โหลดเอกสารอ้างอิงรหัสคำแนะนำสำหรับร้านค้าฉบับสมบูรณ์:

ดาวน์โหลดรหัสคำแนะนำสำหรับร้านค้า (Excel)

คุณยังสามารถติดต่อ support@omise.co สำหรับความช่วยเหลือเพิ่มเติม

แหล่งข้อมูลที่เกี่ยวข้อง