Реалізація серверної верифікації покупок (Receipt Validation)

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Реалізація серверної верифікації покупок (Receipt Validation)
Складний
~2-3 дні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Реалізація серверної верифікації покупок (Receipt Validation)

Клієнт прислав звіт про помилку: користувач купив Premium, отримав токен транзакції, потім відновив додаток з резервної копії на іншому пристрої — і Premium знову активний без повторної оплати. Класика. Причина — валідація тільки на клієнті: додаток перевіряє локальний receipt або trust-флаг від StoreKit, не звіряючись з сервером.

Чому клієнтська валідація — це не валідація

На iOS StoreKit 2 повертає Transaction з підписом Apple. Можна верифікувати підпис локально через Transaction.verificationResult, але це не захищає від replay-атак: зловмисник перехоплює валідний receipt одного користувача і підставляє його в інший акаунт. На Android ситуація аналогічна — BillingClient.queryPurchasesAsync() повертає Purchase об'єкти, які клієнт не повинен трактувати як підтвердження без серверної перевірки purchaseToken.

Найчастіша схема шахрайства — «receipt sharing»: один receipt розповсюджується між користувачами через форуми. Без серверної бази, яка фіксує який originalTransactionId (iOS) або orderId (Android) уже використаний, це не поймати.

Як улаштована нормальна серверна верифікація

Сторона iOS (App Store Server API). Старий підхід — POST на https://buy.itunes.apple.com/verifyReceipt з base64-encoded receipt-data — застарів. Apple просуває App Store Server API v1: клієнт передає серверу transactionId з Transaction.id (StoreKit 2), сервер робить GET /inApps/v1/history/{transactionId} з JWT-токеном (підписаним ES256 ключем з App Store Connect). Відповідь — JWSTransaction, який потрібно декодувати й верифікувати підпис через Apple Root CA.

Паралельно потрібно підписатися на App Store Server Notifications V2: Apple пушить події (DID_RENEW, EXPIRED, REFUND, GRACE_PERIOD_EXPIRED) на ваш endpoint. Без цього статус підписки на сервері застарівує — користувач відмінив підписку, а у вас він ще числиться Premium.

Сторона Android (Google Play Developer API). Для розповсюджувальних покупок — purchases.products.get з packageName, productId, purchaseToken. Для підписок — purchases.subscriptions.v2.get. Авторизація через Service Account з роллю Financial data viewer — це мінімально необхідні права, не давайте Editor на весь проект. Відповідь містить purchaseState (0 = Purchased, 1 = Canceled, 2 = Pending) і acknowledgementState — якщо 0, потрібно викликати purchases.products.acknowledge, інакше Google повертає гроші автоматично через 3 дні.

Ідемпотентність і захист від replay. У базі зберігаємо таблицю purchase_receipts з унікальним індексом по original_transaction_id + product_id. При кожному запиті на верифікацію спочатку перевіряємо наявність запису — якщо вже верифікували з іншим user_id, відповідаємо помилкою. Це й є захист від receipt sharing.

purchase_receipts
  id                    uuid PK
  user_id               uuid FK
  platform              enum('ios','android')
  original_transaction_id varchar UNIQUE (per product)
  product_id            varchar
  purchase_state        smallint
  expires_at            timestamptz  -- для підписок
  raw_payload           jsonb        -- оригінальна відповідь від Apple/Google
  verified_at           timestamptz

Стек та інтеграція

Серверна частина частіше за все Node.js (бібліотека app-store-server-api) або Python (google-auth + googleapiclient). Для Node зручний пакет node-apple-receipt-verify для legacy-endpoint, але краще одразу брати app-store-server-api від Apple — підтримує JWT-авторизацію й верифікацію JWS з коробки.

На стороні клієнта iOS — мінімум коду: отримати Transaction.id з Transaction.all або з updates потоку, надіслати на бекенд. Не передавайте весь appStoreReceiptURL — це legacy, і файл може бути невалідним на симуляторі.

На Android клієнт передає purchaseToken і productId з Purchase.purchaseToken. Важливо: токен може бути одним для кількох productId при апгрейді підписки — урахуйте це в логіці.

Процес роботи

Починаємо з аудиту поточної схеми валідації — де саме перевіряється receipt, є ли серверна база покупок, обробляються ли Server Notifications. Далі проектуємо схему БД і API-ендпоінти, реалізуємо верифікацію для кожної платформи, настроюємо webhook-обробник для Server Notifications, покриваємо тестами з моковими відповідями від Apple/Google. Окремий етап — нагрузкове тестування ендпоінта верифікації, тому що при пікових запусках (акція, фіча в топі App Store) він отримує все відразу.

Терміни — від 2 до 5 днів, залежить від наявності серверної інфраструктури та кількості типів покупок (розповсюджувальні, підписки, consumable, non-consumable). Якщо сервер уже є й потрібно тільки додати верифікацію — ближче до 2 днів. Повна архітектура з нуля плюс міграція існуючих користувачів — до 5.