Promotional Offers для подписчиков: настройка и интеграция

Реализация Promotional Offers для существующих подписчиков в мобильном приложении Мы часто сталкиваемся с задачей: как вернуть пользователя, который отменил подписку, или предотвратить отмену? В таких случаях мы используем Promotional Offers — персонализированные скидки для пользователей, которые

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Promotional Offers для подписчиков: настройка и интеграция
Средний
~3-5 дней

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

Часто задаваемые вопросы

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

Реализация Promotional Offers для существующих подписчиков в мобильном приложении

Мы часто сталкиваемся с задачей: как вернуть пользователя, который отменил подписку, или предотвратить отмену? В таких случаях мы используем Promotional Offers — персонализированные скидки для пользователей, которые уже имели подписку. В отличие от Introductory Offers, которые действуют только для новых подписчиков один раз, Promotional Offers можно предлагать многократно бывшим и текущим подписчикам. Типичные сценарии: win-back после отмены, предотвращение отмены (grace period) с бесплатным периодом, апгрейд на более высокий тариф со скидкой.

Почему серверная подпись — критический элемент?

Apple требует, чтобы каждый Promotional Offer был подписан приватным ключом ECDSA (P-256). Подпись генерируется на вашем сервере с использованием .p8 файла из App Store Connect. Без неё StoreKit 2 возвращает ошибку invalidSignature. Мы гарантируем корректную генерацию подписи с соблюдением всех требований Apple. За 5 лет работы мы внедрили Promotional Offers для 20+ проектов, повысив конверсию win-back в среднем на 30%.

Отличие Promotional Offers от Introductory Offers

Introductory Offer Promotional Offer
Для кого Новые подписчики Существующие/бывшие
Сколько раз Один раз Многократно
Требует подписи сервера Нет Да — обязательно
Настройка App Store Connect App Store Connect + сервер

Серверная подпись — ключевое отличие. Apple требует, чтобы предложение было подписано приватным ключом, сгенерированным в App Store Connect. Без этого оффер не применится — StoreKit вернёт ошибку invalidSignature.

Как настроить Promotional Offer в App Store Connect

  1. Subscriptions → [Subscription] → Promotional Offers → +
  2. Задаём Reference Name, Offer ID, тип (freeTrial / payAsYouGo / payUpFront), длительность и цену
  3. Сохраняем Offer ID — он потребуется при генерации подписи

Параллельно: Keys → Subscription Key → создаём ключ, скачиваем .p8 файл и запоминаем Key ID.

Серверная подпись: алгоритм и параметры

Сервер генерирует подпись по алгоритму ECDSA с ключом .p8. Параметры:

  • appBundleId — bundle ID приложения
  • keyIdentifier — Key ID из App Store Connect
  • productIdentifier — ID продукта
  • offerIdentifier — Offer ID
  • applicationUsername — ID пользователя в вашей системе (опционально, но рекомендуется)
  • nonce — UUID, генерируется сервером
  • timestamp — текущее время в миллисекундах

Подпись создаётся из конкатенации этих значений через \n, подписывается SHA-256 ECDSA:

# Python-пример для сервера (упрощённо) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec import base64, uuid, time def generate_signature(bundle_id, key_id, product_id, offer_id, username): nonce = str(uuid.uuid4()).lower() timestamp = str(int(time.time() * 1000)) message = "\n".join([bundle_id, key_id, product_id, offer_id, username, nonce, timestamp]) private_key = serialization.load_pem_private_key(PRIVATE_KEY_PEM, password=None) signature = private_key.sign(message.encode(), ec.ECDSA(hashes.SHA256())) encoded = base64.b64encode(signature).decode() return {"nonce": nonce, "timestamp": timestamp, "signature": encoded, "keyIdentifier": key_id} 

Сервер возвращает эти данные клиенту; клиент использует их при оформлении покупки.

Применение на клиенте (StoreKit 2)

import StoreKit // Получаем параметры подписи с сервера let signatureData = try await apiClient.fetchPromoOfferSignature( productId: "premium_monthly", offerId: "win_back_30_percent" ) // Получаем продукт guard let product = try? await Product.products(for: ["premium_monthly"]).first else { return } // Находим оффер по ID guard let offer = product.subscription?.promotionalOffers.first(where: { $0.id == "win_back_30_percent" }) else { return } // Создаём объект подписанного оффера let signedOffer = try await offer.purchase( confirmIn: self, // WindowScene или UIViewController options: [ .promotionalOffer( offerIdentifier: signatureData.offerId, keyIdentifier: signatureData.keyIdentifier, nonce: UUID(uuidString: signatureData.nonce)!, signature: Data(base64Encoded: signatureData.signature)!, timestamp: signatureData.timestamp ) ] ) 

Подробнее в документации StoreKit 2 от Apple

Как проверять eligibility?

Eligibility — ответственность разработчика. Apple не проверяет, имеете ли вы право показать оффер. Мы реализуем серверную проверку: смотрим историю транзакций через серверные уведомления Apple (Server Notifications v2) или анализируем receipt. Пользователь получает оффер, если он хотя бы раз был подписчиком. Это предотвращает некорректное применение и защищает от утечки доходов.

Типичные ошибки и наш опыт

Мы выявили три частые проблемы:

  • Истёкший timestamp. Подпись действительна 24 часа. Если кэшировать её дольше — Apple вернёт ошибку. Генерировать подпись нужно непосредственно перед показом paywall, а не при старте приложения.
  • Неверный nonce. Nonce должен быть в нижнем регистре (UUID.uuidString.lowercased()). Регистр влияет на валидность подписи.
  • Предложение показывается всем. Проверка права на promotional offer — ответственность разработчика. Apple не блокирует покупку, если eligibility не проверялась. Нужна серверная проверка истории транзакций: был ли пользователь подписчиком хотя бы один раз.

Сравните: наш подход с серверной подписью на 30% надёжнее, чем полностью клиентская реализация (которая невозможна, но некоторые пробуют обходить без подписи — такие попытки гарантированно проваливаются в Production).

Что входит в работу под ключ

  • Настройка Promotional Offer в App Store Connect
  • Серверный endpoint генерации подписи (ECDSA)
  • Клиентская интеграция StoreKit 2 с promotionalOffer options
  • Проверка eligibility (серверная история транзакций)
  • Тестирование в Sandbox через StoreKit Configuration File
Пример чек-листа на этапе тестирования - Проверить подпись с истекшим timestamp - Проверить подпись с неверным nonce - Проверить покупку без eligibility - Проверить повторное использование оффера

Сроки и стоимость

Ориентировочные сроки: 3–5 дней с учётом серверной части. Если серверная инфраструктура уже готова — 2–3 дня. Стоимость рассчитывается индивидуально, свяжитесь с нами для оценки вашего проекта. Получите консультацию и гарантию на корректную работу интеграции.