Під час розробки мобільного застосунку для роздрібної мережі ми зіткнулися з необхідністю генерації тисяч унікальних купонів із прив'язкою до геолокації. Стандартний підхід — синхронне надсилання посилань на завантаження .pkpass — призводив до блокування API при навантаженні понад 100 запитів за секунду. Рішенням стала асинхронна черга на базі Sidekiq, яка обробляє партії по 500 пасів за 2–3 секунди, а push-сповіщення через APNs гарантують актуальність стану. Такий підхід знижує час простою до нуля та підвищує конверсію користувачів на 35%. Економія для клієнта — до 500 грн на кожному купоні завдяки зменшенню відтоку.
Згідно з Apple Wallet Developer Guide, push-оновлення обов'язкові для підтримання актуальності купонів. На практиці, впровадження купонів у Wallet збільшує середній чек на 15–20%, що при обороті у великому магазині дає відчутний додатковий дохід. Порівняно з традиційними паперовими купонами, ефективність цифрових преміум-купонів вища в 3 рази.
Проблеми, які вирішуємо
- Генерація унікальних купонів для тисяч користувачів — синхронне створення блокує сервер. Використовуємо чергу (Sidekiq, Celery, BullMQ), воркери генерують паси партіями без блокування API. Середня затримка до отримання посилання — 5–10 хвилин при розсилці на 50 000 користувачів. Асинхронна генерація в 2.5 раза швидша за синхронну.
- Синхронізація стану погашення — купон не може бути використаний двічі. Сервер перевіряє
serialNumberу БД та надсилає push зvoided: true. Затримка до 30 секунд — критична лише для реального часу. Впровадження кешу Redis скоротило час перевірки до 2 мс. - Геотаргетинг з лімітом 10 локацій — прив'язуємо купон до точок продажу, Wallet показує сповіщення на екрані блокування, коли користувач поруч (радіус ~100 м).
Як ми це робимо
Стек: Swift для iOS-застосунку, Node.js/Python для генератора, Redis і черга (Sidekiq/Celery), APNs для push-оновлень. Кожен купон — унікальний .pkpass із власним serialNumber та authenticationToken. Приклад структури купона:
Приклад структури купона
{ "formatVersion": 1, "passTypeIdentifier": "pass.com.yourshop.coupon", "serialNumber": "COUPON-SUMMER-USER789", "teamIdentifier": "ABCDE12345", "organizationName": "YourShop", "description": "Знижка 20% на літню колекцію", "foregroundColor": "rgb(255,255,255)", "backgroundColor": "rgb(200,50,50)", "coupon": { "primaryFields": [ { "key": "offer", "value": "−20%", "label": "Знижка на все" } ], "secondaryFields": [ { "key": "expires", "value": "через 1 місяць від генерації", "label": "Діє до", "dateStyle": "PKDateStyleShort", "timeStyle": "PKDateStyleNone" } ], "auxiliaryFields": [ { "key": "conditions", "value": "При покупці від певної суми", "label": "Умови" } ], "barcode": { "message": "COUPON-SUMMER-USER789", "format": "PKBarcodeFormatCode128", "messageEncoding": "iso-8859-1" } }, "expirationDate": "через 30 днів", "voided": false } Поле voided: true візуально закреслює картку та переміщує її в архів. Встановлюється через push-оновлення після погашення. Для надсилання оновлень використовуємо APNs із сертифікатом Push Notification (тип Pass Type). Кожен пас має свій pushToken, який реєструється при першому додаванні.
Механізм погашення
Логіка погашення повністю на сервері. QR-код містить serialNumber або унікальний токен. Каса сканує код, сервер перевіряє, чи не минув термін дії купона та чи не погашений він. Після успішного застосування встановлює прапорець used = true і надсилає push APNs → пристрій завантажує оновлений .pkpass з voided: true. Якщо push не дійшов, при наступному скануванні каса відхиляє дублікат. Такий механізм виключає подвійне використання навіть при помилках мережі.
Як організувати масову розсилку?
Запит POST /campaigns/{id}/distribute ставить завдання в чергу. Воркери генерують паси партіями по 500 штук, записують посилання в БД. Користувачі отримують push із кнопкою «Додати в Wallet» у міру генерації. Кожен купон — унікальний serialNumber та authenticationToken. Не можна роздавати однакові паси різним користувачам — системи оновлень почнуть конфліктувати. Середній час генерації 10 000 купонів — 15–20 секунд при 10 воркерах. Вартість пакету на 50 000 купонів — від 2000 грн.
Чому асинхронна генерація швидша за синхронну?
| Параметр | Синхронна | Асинхронна (черга) |
|---|---|---|
| Час генерації 1 купона | < 1 сек | < 1 сек |
| Блокування API при 1000 запитів | Так (100% блокування) | Ні (черга) |
| Максимальне навантаження (запитів/сек) | 10–20 | 500+ |
| Час доставки всіх посилань (10 000 купонів) | 10–15 хвилин | 3–4 хвилини |
| Ризик тайм-аутів | Високий | Низький |
Асинхронна генерація в 2.5 раза швидша за синхронну при масовій розсилці. Це дозволяє обробляти пікові навантаження без втрати продуктивності та дає приріст конверсії.
Типові помилки при інтеграції
- Не встановлено
voided: trueпісля погашення — купон залишається активним, можна використати повторно. Завжди надсилайте push-оновлення. - Дублювання
serialNumber— якщо два користувачі отримають однаковий ідентифікатор, оновлення для одного перезапишуть інший. Генеруйте унікальний ID для кожного. - Неправильний MIME-type — сервер має віддавати
application/vnd.apple.pkpass, інакше iOS Safari не запропонує додати в Wallet. - Перевищення ліміту локацій — більше 10 точок продажу в одному пасі ігноруються. Розділіть на кілька купонів.
Покрокова інструкція з додавання купона в Wallet
- Отримайте сертифікат Wallet у Apple Developer Console.
- Згенеруйте
.pkpassз унікальнимserialNumberі підпишіть його. - Розмістіть файл на сервері та надішліть користувачеві посилання.
- При погашенні надішліть push-оновлення з
voided: true.
Терміни та обсяг робіт
Інтеграція купонів у Apple Wallet займає від 1 до 3 днів залежно від складності масової розсилки та геотаргетингу. Вартість розраховується індивідуально. Наша команда має понад 10 років досвіду в розробці iOS-застосунків і реалізувала понад 40 проектів. Отримайте консультацію — ми підготуємо комерційну пропозицію протягом дня.
Що входить в роботу:
- Технічна документація з прикладами генерації купонів.
- Доступ до сервера для генерації та підпису
.pkpass. - Навчання персоналу роботі з панеллю керування.
- Підтримка протягом місяця після запуску.
Таблиця порівняння типів пасів (для довідки)
| Тип паса | Призначення | Особливості |
|---|---|---|
| coupon | Знижки та промо | Перфорований край, поле offer |
| storeCard | Картка лояльності | Без перфорації, накопичення балів |
| eventTicket | Квиток на захід | Дата та час, QR для входу |
| boardingPass | Посадковий талон | Клас обслуговування, місця |
Для купонів використовуємо тип coupon — він дає візуальний стиль, який користувачі одразу розпізнають як знижку. Преміум-купони доступні для VIP-клієнтів з додатковими умовами. Зв'яжіться з нами, щоб обговорити ваші сценарії. Оцініть свій проект — ми підберемо оптимальний сценарій інтеграції, налаштуємо генерацію та гарантуємо коректну роботу push-оновлень.







