Усі статті
Deep dive7 хв читання

Є один endpoint, який повертає всю App Store refund history клієнта, і ось що він віддає у відповідь

Endpoint Get Refund History від Apple повертає повну App Store refund history клієнта як підписані транзакції. Ось кожне поле, як токен revision розбиває на сторінки, чому він працює на клієнта, а не на застосунок, і скільки коштує вам пропущене відшкодування.

Сцена робочого столу згори зі смартфоном, паперовою книгою обліку транзакцій та лупою, що ілюструє отримання App Store refund history клієнта через endpoint Get Refund History від Apple

Головне

  • Get Refund History це endpoint App Store Server API, який повертає відшкодовані внутрішні покупки клієнта для вашого застосунку як список підписаних транзакцій, тож ви звіряєте відшкодування та відкликаєте доступ навіть тоді, коли сповіщення так і не дійшло до вас.
  • Ви викликаєте GET /inApps/v2/refund/lookup/{transactionId} з будь-яким ідентифікатором транзакції цього клієнта, і Apple повертає його відшкодування за кожним типом покупки у вашому застосунку, а не лише за тим, про який ви питали.
  • Відповідь має три поля: signedTransactions, до 20 транзакцій JWS на сторінку, відсортованих від найстарішого відшкодування, плюс токен revision та булеве значення hasMore для гортання сторінок.
  • Збережіть кінцевий токен revision. Передайте його назад наступного разу, і Apple поверне лише відшкодування, новіші за цю точку, що перетворює повний дамп історії на короткий список нових рядків за кожного запуску.
  • Кожна декодована транзакція несе revocationDate та revocationReason. revocationReason зі значенням 1 означає, що клієнт отримав відшкодування через фактичну або відчутну проблему у вашому застосунку, а 0 означає іншу причину, наприклад випадкову покупку.
  • Endpoint працює на клієнта, а не на застосунок. Немає жодного виклику, який перелічив би кожне відшкодування у всьому вашому застосунку, тож ви звіряєте на кожен обліковий запис від ідентифікатора транзакції, або читаєте свій потік сповіщень REFUND для огляду по всьому застосунку.
  • Причина це підключити це гроші. Відшкодування, яке ви так і не вловите, тримає обліковий запис активним, і ви далі платите за обчислення, виклики API моделі, сховище та виплати за клієнта, з яким App Store уже розрахувався.

Apple веде для кожного облікового запису клієнта, пов'язаного з вашим застосунком, придатний до запитів запис кожного відшкодування, яке воно надало, і один виклик його повертає. Endpoint називається Get Refund History, він частина App Store Server API, і він віддає вам повну App Store refund history цього клієнта як список підписаних транзакцій. Ви передаєте ідентифікатор транзакції, отримуєте назад те, що Apple відшкодувало, і звіряєте це з тим, що у вас досі увімкнено.

Ось чому це варто робити. Відшкодування, якого ви ніколи не бачите, це відшкодування, за яке ви далі платите. Гроші вже пішли, але обліковий запис лишається активним, і щогодини, поки це так, ви далі витрачаєте на обчислення, виклики API моделі, сховище та будь-яку виплату, прив'язану до цього клієнта. Ваші сповіщення про відшкодування мають вловлювати це в мить, коли воно стається. Get Refund History це запасний варіант на випадок, коли вони цього не роблять, після збою, після розгортання, яке загубило вебхук, або в справі підтримки, де вам потрібна вся картина в одному виклику.

Що повертає endpoint App Store refund history

Ви викликаєте GET /inApps/v2/refund/lookup/{transactionId} до App Store Server API, підписаний тим самим JWT, який ви використовуєте для кожного іншого виклику до нього. Ідентифікатор транзакції у шляху може бути будь-якою транзакцією цього клієнта. Apple читає його як особу, а не як фільтр, і повертає відшкодовані покупки цього клієнта з усього вашого застосунку: витратні, невитратні, автоматично поновлювані та неподовжувані підписки нарівні. Старіша V1 цього endpoint повертала до 50 відшкодувань в одній відповіді і є застарілою. Поточна версія розбиває на сторінки, тож ви обробляєте клієнтів із довгою історією без велетенського корисного навантаження.

Відповідь це три поля

ПолеЩо воно містить
signedTransactionsДо 20 відшкодованих транзакцій цього клієнта, кожна як підписаний JWS, який ви перевіряєте та декодуєте. Відсортовані від найстарішого відшкодування, за revocationDate. Порожній масив означає, що в клієнта немає відшкодувань у вашому застосунку
revisionТокен розбиття на сторінки. Передайте його назад, щоб отримати наступну сторінку, і збережіть останній, щоб наступного разу отримати лише нові відшкодування
hasMoreTrue, коли Apple тримає більше відшкодованих транзакцій, ніж повернула ця сторінка, тож ви викликаєте знову з revision

Що вам каже одна відшкодована транзакція

Кожен запис у signedTransactions це JWS. Перевірте його за ланцюжком сертифікатів Apple, декодуйте, і ви маєте звичайне корисне навантаження транзакції із заповненими полями відшкодування. Ось ті, що тут мають значення.

ПолеЩо воно вам каже
transactionIdІдентифікатор відшкодованої транзакції, ваш ключ зв'язку назад до покупки, яку ви записали
originalTransactionIdІдентифікатор першої покупки в ланцюжку, спосіб пов'язати поновлення підписки між собою
productIdПродукт, який було відшкодовано, щоб ви відкликали правильне право доступу і нічого зайвого
revocationDateЧас UNIX, у мілісекундах, коли Apple відшкодувало транзакцію
revocationReasonЧому Apple її відшкодувало. 1 означає фактичну або відчутну проблему з вашим застосунком, 0 означає іншу причину, наприклад випадкову покупку
price, currencyСума, у milliunits, та її код валюти ISO 4217, щоб ви могли підсумувати повернуті гроші
appAccountTokenUUID, який ви долучили під час покупки, найчистіший спосіб зіставити відшкодування назад із вашим власним користувачем

Токен revision це те, як ви припиняєте перечитувати весь список

Наївний спосіб використати цей endpoint це шукати клієнта й щоразу проходити кожну сторінку. Це працює, і в клієнта з п'ятдесятьма відшкодуваннями це п'ятдесят рядків, які ви вже знали, плюс той один новий. Токен revision існує, щоб убити це марнотратство. Кожна відповідь несе revision. Коли hasMore має значення true, ви передаєте його назад, щоб отримати наступну сторінку. Коли ви доходите до кінця, ви зберігаєте останній revision, який бачили.

Чого цей endpoint не зробить

Є одне очікування, якого треба позбутися, перш ніж на цьому будувати. Get Refund History працює на клієнта, а не на застосунок. Ви не спитаєте в нього про кожне відшкодування, яке ваш застосунок зазнав минулого тижня. Він відповідає на одне питання, які відшкодування має цей обліковий запис, і вам треба прийти з ідентифікатором транзакції для цього облікового запису, щоб його поставити. Розробники постійно натикаються на цю стіну й шукають endpoint відшкодувань для всього застосунку, якого не існує.

Огляд по всьому застосунку живе деінде. Ваш потік App Store Server Notifications надсилає сповіщення REFUND у мить, коли Apple надає кожне з них, а Get Notification History дозволяє вам відтворити цей потік, відфільтрований до типів відшкодувань, за діапазоном дат. Отже поділ чіткий. Сповіщення та їхня історія дають вам потік по всьому застосунку. Get Refund History дає вам авторитетний список одного облікового запису, на вимогу, а це саме те, що вам потрібно за стійкою підтримки або після збою.

Лупа, що зависла над одним підсвіченим рядком паперової книги обліку транзакцій поруч зі смартфоном, ілюструючи пошук відшкодувань одного клієнта в App Store refund history

Скільки коштує вам пропущене відшкодування в грошах

Endpoint це трубопровід. Рахунок це причина, чому ви кладете трубу. Кожне відшкодування в цьому списку це вже повернуті гроші, і єдина змінна, що лишається під вашим контролем, це те, як довго ви далі витрачаєте на обліковий запис, який більше не платить.

Ви далі платите за обслуговування відшкодованого облікового запису

Ціна покупки зникає в мить, коли Apple надає відшкодування. Те, що далі працює, це вартість надання послуги. Для застосунку, який виконує реальну роботу на користувача, це обчислення, виклики API моделі, сховище та будь-яка виплата творцю чи партнеру, прив'язана до їхнього використання. Відшкодований клієнт, чий доступ ви так і не відрізали, це підписка, яку ви фінансуєте з власної кишені. Звіряння з Get Refund History та відкликання за тим, що ви знаходите, це те, як ви вимикаєте цей лічильник, коли сповіщення прослизнуло.

Причина відшкодування 1 це замаскований звіт про дефект

revocationReason коштує вам удвічі, якщо ви його ігноруєте. Перша вартість це саме відшкодування. Друга це кожне майбутнє відшкодування з тієї самої причини. Коли продукт раз у раз повертається з revocationReason 1, фактичною або відчутною проблемою у вашому застосунку, Apple вручає вам позначений зразок того, що змушує клієнтів просити гроші назад. Виведіть із цього тренд на кожен продукт, і ви зможете залатати течу замість виплачувати її по одному відшкодуванню за раз.

Вловити пізно все одно краще, ніж не вловити

Chargeback остаточний перед банком і в іншому магазині тепер несе комісію, яку розробник проковтує. Відшкодування в App Store не таке. Воно врегульоване, але право доступу ваше, щоб відкликати його в мить, коли ви дізнаєтеся. Тож навіть відшкодування, яке ви знайдете на кілька днів пізніше через цей endpoint, варте того, щоб його знайти. Ви не повернете гроші назад, але можете зупинити витрату, яка досі бігла позаду нього.

Як це поєднується зі сповіщеннями та з Google

Сприймайте ці частини як одну систему. Сповіщення REFUND це живий сигнал, надісланий на ваш сервер у мить, коли Apple вирішує. Get Refund History це джерело істини на основі запиту для одного клієнта, виклик, який ви робите, коли push не спрацював або коли людині потрібен повний обліковий запис перед очима. З боку Google Play форма це та сама ідея з іншими назвами: VoidedPurchaseNotification надсилається в реальному часі, а Voided Purchases API це список, який ви запитуєте. Обидва магазини дають вам потік та книгу обліку. Помилка це довіряти лише потоку, бо потоки зриваються.

Підключення цього способом RefundHalt

Цикл малий, щойно кожна частина на своєму місці. Візьміть сповіщення REFUND як тригер. Звіряйте з Get Refund History, щоб загублений вебхук ніколи не лишив відшкодований обліковий запис активним. Декодуйте кожну транзакцію, прив'яжіть її за appAccountToken або transactionId назад до вашого користувача, прочитайте revocationReason, щоб відшкодування через дефект було позначене, а не просто відкладене, і відкличте точне право доступу замість усього облікового запису. Гортайте сторінки токеном revision, щоб ви читали нові відшкодування, а не старі.

Це та частина, яку RefundHalt веде за вас. Він слухає сповіщення про відшкодування, звертається до Get Refund History, коли потребує авторитетного списку, перевіряє кожну підписану транзакцію, відкликає точну покупку та зберігає revision, щоб кожен прохід читав лише те, що змінилося. Ви отримуєте відрізаний доступ за секунди та чистий запис того, кому відшкодували, за що й чому, без того, щоб самому піднімати опитування та перевірку JWS.

Поширені запитання

Як мені побачити кожне відшкодування у всьому моєму застосунку, а не лише одного клієнта?
Через Get Refund History цього не зробити, бо він працює на клієнта й потребує ідентифікатора транзакції для облікового запису, про який ви питаєте. Для огляду по всьому застосунку скористайтеся своїм потоком App Store Server Notifications, який надсилає сповіщення REFUND для кожного відшкодування в мить, коли Apple його надає, та Get Notification History, щоб відтворити цей потік, відфільтрований до типів відшкодувань, за діапазоном дат.
Скільки відшкодувань повертає endpoint Get Refund History?
Поточна версія повертає до 20 відшкодованих транзакцій на сторінку, відсортованих від найстарішого відшкодування, і гортає решту токеном revision, коли hasMore має значення true. Застарілий endpoint V1 повертав до 50 в одній відповіді. Немає обмеження на загальну кількість, тож клієнт із довгою історією просто охоплює більше сторінок.
Для чого потрібен токен revision?
Це те, як ви гортаєте сторінки, і те, як ви уникаєте перечитування всієї історії клієнта щоразу. Кожна відповідь містить revision. Ви передаєте його назад, щоб отримати наступну сторінку, і зберігаєте останній, щоб ваш наступний пошук повертав лише відшкодування, новіші за цю точку. Це тримає заплановане звіряння на короткому списку нових рядків.
Що означає revocationReason у відшкодованій транзакції?
Це причина, чому Apple відшкодувало транзакцію. Значення 1 означає, що клієнт отримав відшкодування через фактичну або відчутну проблему всередині вашого застосунку, а 0 означає іншу причину, наприклад випадкову покупку. revocationDate каже вам, коли сталося відшкодування, у мілісекундах UNIX. Читання revocationReason дозволяє відокремити дефект продукту від разового відшкодування через жаль.
Чи потрібне мені це досі, якщо я вже обробляю сповіщення REFUND?
Так, як запасний варіант. Сповіщення це живий сигнал, але push може не дійти під час збою, невдалого розгортання чи зміни вебхука, а пропущене відшкодування лишає відшкодований обліковий запис активним і таким, що коштує вам грошей. Get Refund History це джерело істини на основі запиту, з яким ви звіряєтеся, щоб ніщо не лишалося увімкненим із того, що Apple вже відшкодувало.

Джерела та додаткове читання

RefundHalt

Автопілот повернень для App Store і Google Play

Читайте далі

Наступний запит на повернення вже в дорозі.

Налаштуйте RefundHalt за час, потрібний, щоб прочитати черговий лист у підтримку про повернення, яке ви не встигли оскаржити.