บทความทั้งหมด
Deep diveใช้เวลาอ่าน 7 นาที

มี endpoint หนึ่งเดียวที่คืนประวัติการคืนเงิน App Store ทั้งหมดของลูกค้า และนี่คือสิ่งที่มันส่งกลับมาให้

endpoint Get Refund History ของ Apple คืนประวัติการคืนเงิน App Store ทั้งหมดของลูกค้าในรูปแบบ signed transactions นี่คือทุกฟิลด์ วิธีที่ revision token แบ่งหน้า เหตุใดมันจึงเป็นรายลูกค้าไม่ใช่รายแอป และการคืนเงินที่คุณพลาดไปทำให้คุณเสียเท่าไหร่

ภาพโต๊ะทำงานมองจากด้านบนที่มีสมาร์ตโฟน สมุดบัญชีธุรกรรมแบบกระดาษ และแว่นขยาย แสดงถึงการดึงประวัติการคืนเงิน App Store ของลูกค้าจาก endpoint Get Refund History ของ Apple

ประเด็นสำคัญ

  • Get Refund History เป็น endpoint ของ App Store Server API ที่คืนการซื้อ in-app ที่ถูกคืนเงินของลูกค้าในแอปของคุณเป็นรายการ signed transactions เพื่อให้คุณกระทบยอดการคืนเงินและเพิกถอนสิทธิ์การเข้าถึงได้ แม้ว่าจะไม่มี notification ใดมาถึงคุณเลยก็ตาม
  • คุณเรียก GET /inApps/v2/refund/lookup/{transactionId} ด้วย transaction id ใดก็ได้ของลูกค้ารายนั้น แล้ว Apple จะคืนการคืนเงินของพวกเขาในทุกประเภทการซื้อในแอปของคุณ ไม่ใช่แค่รายการที่คุณถามถึง
  • การตอบกลับมีสามฟิลด์: signedTransactions มากถึง 20 JWS transactions ต่อหน้าที่เรียงจากการคืนเงินเก่าสุดก่อน พร้อมด้วย revision token และค่า hasMore แบบ boolean สำหรับการแบ่งหน้า
  • จัดเก็บ revision token ตัวสุดท้ายไว้ ส่งมันกลับไปในครั้งถัดไป แล้ว Apple จะคืนเฉพาะการคืนเงินที่ใหม่กว่าจุดนั้น ซึ่งเปลี่ยนการดึงประวัติทั้งหมดให้กลายเป็นรายการสั้นๆ ของแถวใหม่ในทุกครั้งที่รัน
  • แต่ละ transaction ที่ถอดรหัสแล้วจะมี revocationDate และ revocationReason ค่า revocationReason เท่ากับ 1 หมายความว่าลูกค้าคืนเงินเพราะปัญหาจริงหรือที่รับรู้ในแอปของคุณ และ 0 หมายถึงเหตุผลอื่นเช่นการซื้อโดยบังเอิญ
  • endpoint นี้เป็นรายลูกค้า ไม่ใช่รายแอป ไม่มีการเรียกเดียวที่แสดงรายการการคืนเงินทุกรายการทั่วทั้งแอปของคุณ ดังนั้นคุณจึงกระทบยอดเป็นรายบัญชีจาก transaction id หรืออ่านฟีด notification แบบ REFUND ของคุณเพื่อดูภาพรวมทั้งแอป
  • เหตุผลที่ต้องเชื่อมต่อมันคือเรื่องเงิน การคืนเงินที่คุณไม่เคยจับได้จะทำให้บัญชียังคงใช้งานอยู่ และคุณยังคงจ่ายค่า compute, model API calls, storage และ payouts ให้ลูกค้าที่ App Store ได้ชดใช้ให้เขาไปแล้ว

Apple เก็บบันทึกที่ค้นหาได้ของทุกการคืนเงินที่ได้อนุมัติบนบัญชีของลูกค้าสำหรับแอปของคุณ และการเรียกเพียงครั้งเดียวจะคืนมันกลับมา endpoint คือ Get Refund History ซึ่งเป็นส่วนหนึ่งของ App Store Server API และมันจะส่งประวัติการคืนเงิน App Store ทั้งหมดของลูกค้ารายนั้นให้คุณเป็นรายการ signed transactions คุณส่ง transaction id เข้าไป คุณได้สิ่งที่ Apple คืนเงินกลับมา แล้วคุณกระทบยอดมันกับสิ่งที่คุณยังเปิดใช้งานอยู่

นี่คือเหตุผลว่าทำไมคุณจึงควรใส่ใจ การคืนเงินที่คุณไม่เคยเห็นคือการคืนเงินที่คุณยังคงจ่ายอยู่ เงินหายไปแล้ว แต่บัญชียังคงใช้งานอยู่ และทุกชั่วโมงที่มันยังอยู่ คุณยังคงใช้จ่ายกับ compute, model API calls, storage และ payout ใดๆ ที่ผูกกับลูกค้ารายนั้น การแจ้งเตือนการคืนเงินของคุณมีไว้เพื่อจับสิ่งนี้ในทันทีที่มันเกิดขึ้น Get Refund History คือแนวรับสุดท้ายสำหรับตอนที่มันจับไม่ได้ หลังเกิดเหตุขัดข้อง หลัง deploy ที่ทำ webhook หลุด หรือในเคสฝ่ายสนับสนุนที่คุณต้องการภาพทั้งหมดในการเรียกครั้งเดียว

endpoint ประวัติการคืนเงิน App Store คืนอะไรกลับมา

คุณเรียก GET /inApps/v2/refund/lookup/{transactionId} ไปยัง App Store Server API โดยลงนามด้วย JWT ตัวเดียวกับที่คุณใช้ในทุกการเรียกอื่นๆ ของมัน transaction id ในเส้นทางสามารถเป็น transaction ใดก็ได้ของลูกค้ารายนั้น Apple อ่านมันเป็นตัวระบุตัวตน ไม่ใช่ตัวกรอง และคืนการซื้อที่ถูกคืนเงินของลูกค้ารายนั้นทั่วทั้งแอปของคุณ ทั้ง consumables, non-consumables, auto-renewable และ non-renewing subscriptions เหมือนกันหมด V1 รุ่นเก่าของ endpoint นี้เคยคืนการคืนเงินได้มากถึง 50 รายการในการตอบกลับครั้งเดียวและตอนนี้เลิกใช้แล้ว รุ่นปัจจุบันแบ่งหน้า ดังนั้นคุณจึงจัดการลูกค้าที่มีประวัติยาวได้โดยไม่ต้องมี payload ขนาดใหญ่

การตอบกลับมีสามฟิลด์

ฟิลด์สิ่งที่มันเก็บไว้
signedTransactionstransactions ที่ถูกคืนเงินมากถึง 20 รายการสำหรับลูกค้ารายนี้ แต่ละรายการเป็น JWS ที่ลงนามซึ่งคุณตรวจสอบและถอดรหัส เรียงจากการคืนเงินเก่าสุดก่อนตาม revocationDate array ว่างหมายความว่าลูกค้าไม่มีการคืนเงินในแอปของคุณ
revisionโทเคนสำหรับแบ่งหน้า ส่งมันกลับไปเพื่อรับหน้าถัดไป และเก็บตัวสุดท้ายไว้เพื่อดึงเฉพาะการคืนเงินใหม่ในครั้งถัดไป
hasMoreTrue เมื่อ Apple มี transactions ที่ถูกคืนเงินมากกว่าที่หน้านี้คืนกลับมา ดังนั้นคุณจึงเรียกอีกครั้งด้วย revision

transaction ที่ถูกคืนเงินหนึ่งรายการบอกอะไรคุณ

แต่ละรายการใน signedTransactions เป็น JWS ตรวจสอบมันกับสายใบรับรองของ Apple ถอดรหัสมัน แล้วคุณจะได้ payload ของ transaction ตามปกติที่มีฟิลด์การคืนเงินใส่ค่าไว้ นี่คือฟิลด์ที่สำคัญที่นี่

ฟิลด์สิ่งที่มันบอกคุณ
transactionIdid ของ transaction ที่ถูกคืนเงิน คีย์เชื่อมของคุณกลับไปยังการซื้อที่คุณบันทึกไว้
originalTransactionIdid ของการซื้อครั้งแรกในสายนั้น วิธีที่คุณผูกการต่ออายุของ subscription เข้าด้วยกัน
productIdผลิตภัณฑ์ที่ถูกคืนเงิน เพื่อให้คุณเพิกถอน entitlement ที่ถูกต้องและไม่ใช่อย่างอื่น
revocationDateเวลา UNIX เป็นมิลลิวินาที ที่ Apple คืนเงิน transaction นั้น
revocationReasonเหตุผลที่ Apple คืนเงินมัน 1 หมายถึงปัญหาจริงหรือที่รับรู้ในแอปของคุณ 0 หมายถึงเหตุผลอื่นเช่นการซื้อโดยบังเอิญ
price, currencyจำนวนเงินเป็นหน่วย milliunits และรหัสสกุลเงิน ISO 4217 ของมัน เพื่อให้คุณรวมยอดเงินที่คืนได้
appAccountTokenUUID ที่คุณแนบมาตอนซื้อ วิธีที่สะอาดที่สุดในการจับคู่การคืนเงินกลับไปยังผู้ใช้ของคุณเอง

revision token คือวิธีที่คุณหยุดอ่านรายการทั้งหมดซ้ำ

วิธีที่ไร้เดียงสาในการใช้ endpoint นี้คือค้นหาลูกค้าและเดินผ่านทุกหน้าทุกครั้ง มันได้ผล และบนลูกค้าที่มีการคืนเงินห้าสิบรายการ มันคือห้าสิบแถวที่คุณรู้อยู่แล้วบวกกับแถวใหม่หนึ่งแถว revision token มีอยู่เพื่อกำจัดความสูญเปล่านั้น การตอบกลับแต่ละครั้งมี revision เมื่อ hasMore เป็น true คุณส่งมันกลับไปเพื่อรับหน้าถัดไป เมื่อคุณไปถึงจุดสิ้นสุด คุณเก็บ revision ตัวสุดท้ายที่คุณเห็นไว้

สิ่งที่ endpoint นี้จะไม่ทำ

มีความคาดหวังหนึ่งอย่างที่ต้องละทิ้งก่อนที่คุณจะสร้างบนมัน Get Refund History เป็นรายลูกค้า ไม่ใช่รายแอป คุณไม่สามารถขอมันให้แสดงทุกการคืนเงินที่แอปของคุณได้รับเมื่อสัปดาห์ที่แล้ว มันตอบคำถามเดียว คือบัญชีนี้มีการคืนเงินอะไรบ้าง และคุณต้องมาพร้อม transaction id ของบัญชีนั้นเพื่อจะถามมัน นักพัฒนาชนกำแพงนี้อยู่ตลอดและออกไปมองหา endpoint การคืนเงินทั้งแอปที่ไม่มีอยู่จริง

ภาพรวมทั้งแอปอยู่ที่อื่น ฟีด App Store Server Notifications ของคุณส่ง notification แบบ REFUND ในทันทีที่ Apple อนุมัติแต่ละรายการ และ Get Notification History ให้คุณเล่นฟีดนั้นซ้ำโดยกรองเป็นประเภทการคืนเงินในช่วงวันที่ที่กำหนด ดังนั้นการแบ่งจึงชัดเจน Notifications และประวัติของมันให้กระแสข้อมูลทั้งแอปแก่คุณ Get Refund History ให้รายการที่เชื่อถือได้ของหนึ่งบัญชีแก่คุณตามต้องการ ซึ่งเป็นสิ่งที่คุณต้องการที่โต๊ะฝ่ายสนับสนุนหรือหลังเกิดเหตุขัดข้อง

แว่นขยายลอยอยู่เหนือแถวหนึ่งที่ถูกไฮไลต์ของสมุดบัญชีธุรกรรมแบบกระดาษข้างสมาร์ตโฟน แสดงถึงการค้นหาการคืนเงินของลูกค้าคนเดียวในประวัติการคืนเงิน App Store

การคืนเงินที่พลาดไปทำให้คุณเสียเงินเท่าไหร่

endpoint คือระบบท่อ ใบเรียกเก็บเงินคือเหตุผลที่คุณวางท่อ ทุกการคืนเงินในรายการนั้นคือเงินที่คืนไปแล้ว และตัวแปรเดียวที่เหลือในการควบคุมของคุณคือคุณจะใช้จ่ายกับบัญชีที่ไม่จ่ายอีกต่อไปนานแค่ไหน

คุณยังคงจ่ายเพื่อให้บริการบัญชีที่ถูกคืนเงิน

ราคาซื้อหายไปในทันทีที่ Apple อนุมัติการคืนเงิน สิ่งที่ยังคงทำงานอยู่คือต้นทุนของการส่งมอบ สำหรับแอปที่ทำงานจริงต่อผู้ใช้แต่ละคน นั่นคือ compute, model API calls, storage และ payout ใดๆ ของครีเอเตอร์หรือพาร์ตเนอร์ที่ผูกกับการใช้งานของพวกเขา ลูกค้าที่ถูกคืนเงินซึ่งคุณไม่เคยตัดการเข้าถึงคือ subscription ที่คุณออกเงินจ่ายจากกระเป๋าตัวเอง การกระทบยอดกับ Get Refund History และเพิกถอนตามสิ่งที่คุณพบคือวิธีที่คุณปิดมิเตอร์นั้นเมื่อ notification หลุดรอดไป

เหตุผลการคืนเงินที่เป็น 1 คือรายงานข้อบกพร่องที่แฝงตัวอยู่

revocationReason ทำให้คุณเสียสองเท่าหากคุณเพิกเฉยต่อมัน ต้นทุนแรกคือการคืนเงินนั้นเอง ต้นทุนที่สองคือทุกการคืนเงินในอนาคตจากสาเหตุเดียวกัน เมื่อผลิตภัณฑ์หนึ่งกลับมาเรื่อยๆ ด้วย revocationReason เท่ากับ 1 คือปัญหาจริงหรือที่รับรู้ในแอปของคุณ Apple กำลังส่งตัวอย่างที่ติดป้ายกำกับให้คุณว่าอะไรทำให้ลูกค้าขอเงินคืน จับแนวโน้มของมันตามผลิตภัณฑ์แล้วคุณจะแก้รอยรั่วได้แทนที่จะจ่ายมันออกไปทีละการคืนเงิน

จับได้ช้ายังดีกว่าจับไม่ได้

chargeback เป็นที่สิ้นสุดกับธนาคาร และบนอีกสโตร์หนึ่ง ตอนนี้มีค่าธรรมเนียมที่นักพัฒนาต้องแบกรับ การคืนเงินของ App Store ไม่ใช่แบบนั้น มันยุติแล้ว แต่ entitlement เป็นของคุณที่จะเพิกถอนในทันทีที่คุณรู้ ดังนั้นแม้แต่การคืนเงินที่คุณพบช้าไปหลายวันผ่าน endpoint นี้ก็ยังคุ้มค่าที่จะพบ คุณไม่สามารถทวงเงินคืนได้ แต่คุณสามารถหยุดการใช้จ่ายที่ยังคงวิ่งอยู่เบื้องหลังมันได้

สิ่งนี้เข้ากับ notifications และกับ Google อย่างไร

คิดถึงชิ้นส่วนต่างๆ เป็นระบบเดียว notification แบบ REFUND คือสัญญาณสด ถูกส่งไปยังเซิร์ฟเวอร์ของคุณเมื่อ Apple ตัดสินใจ Get Refund History คือแหล่งข้อมูลความจริงแบบ pull สำหรับลูกค้าคนเดียว การเรียกที่คุณทำเมื่อการ push ล้มเหลวหรือเมื่อมีคนต้องการดูบัญชีทั้งหมดต่อหน้า ในฝั่ง Google Play รูปแบบก็เป็นแนวคิดเดียวกันด้วยชื่อที่ต่างกัน: VoidedPurchaseNotification push แบบเรียลไทม์ และ Voided Purchases API คือรายการที่คุณดึง ทั้งสองสโตร์ให้กระแสข้อมูลและสมุดบัญชีแก่คุณ ความผิดพลาดคือการเชื่อเฉพาะกระแสข้อมูลอย่างเดียว เพราะกระแสข้อมูลนั้นตกหล่นได้

การเชื่อมต่อมันในแบบของ RefundHalt

ลูปนั้นเล็กเมื่อทุกชิ้นส่วนเข้าที่แล้ว นำ notification แบบ REFUND มาเป็นตัวกระตุ้น กระทบยอดกับ Get Refund History เพื่อให้ webhook ที่หลุดไม่เคยทิ้งบัญชีที่ถูกคืนเงินให้ยังคงใช้งานอยู่ ถอดรหัสแต่ละ transaction จับคู่มันด้วย appAccountToken หรือ transactionId กลับไปยังผู้ใช้ของคุณ อ่าน revocationReason เพื่อให้การคืนเงินจากข้อบกพร่องถูกทำเครื่องหมายไม่ใช่แค่เก็บเข้าแฟ้ม และเพิกถอน entitlement ที่แม่นยำแทนที่จะเป็นทั้งบัญชี แบ่งหน้าด้วย revision token เพื่อให้คุณอ่านการคืนเงินใหม่ ไม่ใช่ของเก่า

นี่คือส่วนที่ RefundHalt รันให้คุณ มันคอยฟังการแจ้งเตือนการคืนเงิน ถอยกลับไปใช้ Get Refund History เมื่อมันต้องการรายการที่เชื่อถือได้ ตรวจสอบทุก signed transaction เพิกถอนการซื้อที่แม่นยำ และเก็บ revision ไว้เพื่อให้แต่ละรอบอ่านเฉพาะสิ่งที่เปลี่ยนแปลง คุณได้การตัดการเข้าถึงภายในไม่กี่วินาทีและบันทึกที่สะอาดว่าใครถูกคืนเงิน สำหรับอะไร และเพราะอะไร โดยไม่ต้องตั้งระบบ polling และการตรวจสอบ JWS ขึ้นมาเอง

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

ฉันจะดูทุกการคืนเงินทั่วทั้งแอปของฉัน ไม่ใช่แค่ลูกค้าคนเดียวได้อย่างไร
คุณทำไม่ได้ด้วย Get Refund History เพราะมันเป็นรายลูกค้าและต้องการ transaction id สำหรับบัญชีที่คุณกำลังถามถึง สำหรับภาพรวมทั้งแอป ให้ใช้ฟีด App Store Server Notifications ของคุณ ซึ่งส่ง notification แบบ REFUND สำหรับการคืนเงินแต่ละรายการเมื่อ Apple อนุมัติ และ Get Notification History เพื่อเล่นฟีดนั้นซ้ำโดยกรองเป็นประเภทการคืนเงินในช่วงวันที่ที่กำหนด
endpoint Get Refund History คืนการคืนเงินกี่รายการ
รุ่นปัจจุบันคืน transactions ที่ถูกคืนเงินมากถึง 20 รายการต่อหน้า เรียงจากการคืนเงินเก่าสุดก่อน และแบ่งหน้าส่วนที่เหลือด้วย revision token เมื่อ hasMore เป็น true endpoint V1 ที่เลิกใช้แล้วเคยคืนมากถึง 50 รายการในการตอบกลับครั้งเดียว ไม่มีเพดานสำหรับยอดรวม ดังนั้นลูกค้าที่มีประวัติยาวก็เพียงกระจายไปหลายหน้ามากขึ้น
revision token มีไว้ทำอะไร
มันคือวิธีที่คุณแบ่งหน้าและวิธีที่คุณหลีกเลี่ยงการอ่านประวัติทั้งหมดของลูกค้าซ้ำทุกครั้ง การตอบกลับแต่ละครั้งมี revision คุณส่งมันกลับไปเพื่อดึงหน้าถัดไป และคุณจัดเก็บตัวสุดท้ายไว้เพื่อให้การค้นหาครั้งถัดไปคืนเฉพาะการคืนเงินที่ใหม่กว่าจุดนั้น นั่นทำให้การกระทบยอดตามกำหนดเหลือเพียงรายการสั้นๆ ของแถวใหม่
revocationReason ใน transaction ที่ถูกคืนเงินหมายความว่าอย่างไร
มันคือเหตุผลที่ Apple คืนเงิน transaction นั้น ค่า 1 หมายความว่าลูกค้าคืนเงินเพราะปัญหาจริงหรือที่รับรู้ภายในแอปของคุณ และ 0 หมายถึงเหตุผลอื่น เช่นการซื้อโดยบังเอิญ revocationDate บอกคุณว่าการคืนเงินเกิดขึ้นเมื่อใด เป็นหน่วย UNIX มิลลิวินาที การอ่าน revocationReason ช่วยให้คุณแยกข้อบกพร่องของผลิตภัณฑ์ออกจากการคืนเงินเพราะเสียใจครั้งเดียวได้
ฉันยังต้องใช้สิ่งนี้อยู่ไหมถ้าฉันจัดการ notification แบบ REFUND อยู่แล้ว
ใช่ ในฐานะแนวรับสุดท้าย Notifications คือสัญญาณสด แต่การ push อาจส่งมาถึงไม่สำเร็จระหว่างเกิดเหตุขัดข้อง deploy ที่ผิดพลาด หรือการเปลี่ยน webhook และการคืนเงินที่พลาดไปจะทิ้งบัญชีที่ถูกคืนเงินให้ยังคงใช้งานอยู่และทำให้คุณเสียเงิน Get Refund History คือแหล่งข้อมูลความจริงแบบ pull ที่คุณกระทบยอดด้วย เพื่อไม่ให้มีสิ่งใดยังเปิดใช้งานอยู่ที่ Apple ได้คืนเงินไปแล้ว

แหล่งข้อมูลและเนื้อหาเพิ่มเติม

RefundHalt

ระบบอัตโนมัติสำหรับการคืนเงินบน App Store และ Google Play

อ่านต่อ

Deep diveใช้เวลาอ่าน 7 นาที

แอปของคุณสามารถแสดงชีตคำขอคืนเงินภายในแอปได้ และนี่คือสิ่งที่ Apple ทำหลังจากลูกค้าแตะส่ง

คำขอคืนเงินภายในแอปของ Apple ให้ลูกค้าขอคืนเงินได้โดยไม่ต้องออกจากแอปของคุณ บนชีตที่ Apple สร้างและตรวจสอบเอง นี่คือสิ่งที่ beginRefundRequest ส่งคืน นาฬิกา CONSUMPTION_REQUEST และ 48 ชั่วโมงที่มันเริ่มจับเวลาบนเซิร์ฟเวอร์ของคุณ และปุ่มนี้คุ้มค่าที่จะปล่อยใช้งานหรือไม่

Deep diveใช้เวลาอ่าน 8 นาที

เมื่อการซื้อบน Google Play ถูกคืนเงินหรือถูก chargeback, Voided Purchases API คือวิธีที่ทำให้คุณรู้

Google Play จะเพิกถอนการซื้อแบบเงียบ ๆ เมื่อมันถูกคืนเงินหรือถูก chargeback. Voided Purchases API คือรายการของออร์เดอร์เหล่านั้น เพื่อให้คุณเพิกถอนสิทธิ์การเข้าถึงได้. นี่คือทุกฟิลด์ หน้าต่าง 30 วัน ตัวเลือก revoke ที่ซ่อนออร์เดอร์ และค่าใช้จ่ายของมัน

คำขอคืนเงินครั้งต่อไปกำลังมา

ตั้งค่า RefundHalt ได้ในเวลาพอ ๆ กับการอ่านอีเมลฝ่ายช่วยเหลืออีกฉบับเกี่ยวกับการคืนเงินที่คุณไม่มีโอกาสโต้แย้ง