О насБлогКонтакты
Мобильная разработка5 сентября 2012 г. 4 мин 15

SMS-платежи до App Store: как работала мобильная коммерция в Казнете в 2012 году

AunimedaAunimeda
📋 Содержание

SMS-платежи до App Store: как работала мобильная коммерция в Казнете в 2012 году

В 2012 году мы работали над проектом мобильных платежей для одного из алматинских ретейлеров. Задача: дать пользователям возможность оплатить заказ с телефона. Звучит просто. Реальность была совсем другой.

App Store существовал — iPhone 5 уже вышел. Но доля смартфонов среди пользователей нашего клиента составляла 22%. Остальные 78% — кнопочные телефоны с поддержкой WAP, USSD и SMS. Делать только iOS-решение означало игнорировать большинство аудитории.


Три реальных платёжных канала в Казнете 2012

1. Премиум-SMS через контент-провайдеров

Пользователь отправлял SMS на короткий номер (например, 7171), в ответ получал код подтверждения, вводил его на сайте. Оператор списывал сумму с мобильного счёта и передавал её контент-провайдеру за вычетом комиссии (25–40%).

Пользователь → SMS "PAY 1500" на 7171
Оператор → проверяет баланс пользователя
Оператор → списывает 1500 тенге с баланса
Оператор → HTTP POST на callback URL контент-провайдера: 
           {"msisdn":"77012345678","amount":1500,"ref":"TX123456"}
Контент-провайдер → HTTP POST на наш webhook:
           {"transaction_id":"TX123456","amount":1035,"status":"success"}
           # 1035 = 1500 минус 31% комиссия

Наш webhook на PHP:

// sms_callback.php
$transactionId = $_POST['transaction_id'];
$amount        = (int) $_POST['amount'];
$status        = $_POST['status'];
$hmac          = $_POST['hmac'];

// Проверка подписи запроса
$expected = hash_hmac('sha1', $transactionId . $amount . $status, PROVIDER_SECRET);
if (!hash_equals($expected, $hmac)) {
    http_response_code(403);
    exit('Invalid signature');
}

if ($status === 'success') {
    $order = Order::findByTransactionRef($transactionId);
    $order->markPaid($amount);
    
    // Отправить SMS с подтверждением пользователю
    SmsGateway::send($order->phone, "Оплата {$amount} тенге принята. Заказ #{$order->id}");
}

http_response_code(200);
echo 'OK';

Главная проблема: комиссия 25–40%. Для товаров с низкой маржой это было неприемлемо. SMS-платежи работали для цифровых товаров (контент, игровая валюта) и не работали для физических.

2. USSD-сессии

USSD (*100# и аналоги) — это интерактивное меню прямо в телефоне, без интернета. Оператор открывает USSD-сессию и передаёт ввод пользователя на наш сервер через специальный протокол.

Пользователь набирает: *250*ORDER_ID#
Оператор открывает USSD-сессию, POST на наш сервер:
{
  "session_id": "sess_abc123",
  "msisdn": "77012345678",
  "input": "ORDER_ID",
  "type": "BEGIN"
}

Наш сервер отвечает:
{
  "session_id": "sess_abc123",
  "message": "Заказ #1234 на сумму 8500 тенге.\n1. Оплатить\n2. Отмена",
  "type": "CON"  // CON = продолжить сессию, END = завершить
}

Пользователь нажимает "1":
{
  "session_id": "sess_abc123",
  "input": "1",
  "type": "CON"
}

Наш сервер:
{
  "message": "Подтвердите оплату 8500 тенге.\n1. Да\n2. Нет",
  "type": "CON"
}

USSD-сессия — синхронная и короткая (таймаут 3–5 минут). Вся логика должна быть stateful: хранить состояние сессии между запросами.

class UssdSession {
    private $redis;
    
    public function handle(string $sessionId, string $msisdn, string $input, string $type): array {
        $state = $this->redis->get("ussd:{$sessionId}") 
                 ? json_decode($this->redis->get("ussd:{$sessionId}"), true)
                 : ['step' => 'init'];
        
        switch ($state['step']) {
            case 'init':
                $orderId = trim($input);
                $order   = Order::findById($orderId);
                
                if (!$order || $order->phone !== $msisdn) {
                    return $this->end("Заказ не найден.");
                }
                
                $this->saveState($sessionId, ['step' => 'confirm', 'order_id' => $orderId]);
                return $this->cont("Заказ #{$orderId}: {$order->amount} тг.\n1. Оплатить\n2. Отмена");
            
            case 'confirm':
                if ($input === '1') {
                    $this->processPayment($state['order_id'], $msisdn);
                    return $this->end("Оплата принята. Спасибо.");
                }
                return $this->end("Отменено.");
        }
    }
    
    private function saveState(string $sessionId, array $state): void {
        $this->redis->setex("ussd:{$sessionId}", 300, json_encode($state));
    }
}

USSD работал на любом телефоне с SIM-картой, не требовал интернета и имел комиссию 5–10% — значительно лучше, чем SMS.

3. WAP-сайт для смартфонов

Для смартфонов без нормального браузера (Symbian, ранний Android с маленькими экранами) делали отдельный WAP-вариант с минимальным HTML:

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
  <style>
    /* Максимум 5KB CSS — WAP-браузеры не любят больше */
    body { font-size: 14px; margin: 10px; }
    .btn { display: block; padding: 12px; background: #0070c0; color: #fff; text-align: center; }
  </style>
</head>
<body>
  <p>Заказ #<?= $order->id ?></p>
  <p>Сумма: <?= $order->amount ?> тг.</p>
  <a class="btn" href="/wap/pay?order=<?= $order->id ?>&token=<?= $token ?>">Оплатить</a>
</body>
</html>

WAP-сайт переадресовывал на страницу оплаты Казкома (они имели WAP-версию процессинга) и получал callback после подтверждения.


Архитектура, которая получилась

В итоге у нас была единая платёжная абстракция, которая выбирала канал в зависимости от устройства:

class PaymentRouter {
    public function route(Order $order, string $userAgent): PaymentChannel {
        if ($this->isSmartphone($userAgent)) {
            return new KaskomWebChannel($order);  // Полноценная веб-страница
        }
        
        if ($this->isMidRange($userAgent)) {
            return new WapChannel($order);         // WAP-страница
        }
        
        // Кнопочный телефон
        return new UssdChannel($order);            // USSD-меню
    }
}

Что изменилось к 2013

К концу 2012 — началу 2013 ситуация начала быстро меняться: проникновение смартфонов росло, Kazkom и Халык выпустили нормальные мобильные SDK. USSD и WAP из основных каналов превратились в резервные.

Но эти полтора года работы с SMS, USSD и WAP научили нас главному: платёжная система должна проектироваться под реальную аудиторию, а не под устройство разработчика. В 2012 году реальная аудитория Казахстана сидела на кнопочных телефонах. Игнорировать её означало потерять рынок.

Тот же принцип мы применяем сегодня при выборе между Kaspi Pay, Apple Pay и банковскими картами — смотрим на статистику платежей реальных пользователей, а не на то, что удобнее интегрировать.

Читайте также

Разработка мобильного приложения в Алматы - сколько стоит и с чего начатьaunimeda
Мобильная разработка

Разработка мобильного приложения в Алматы - сколько стоит и с чего начать

Стоимость разработки мобильного приложения в Алматы в 2026 году. iOS, Android, Flutter - что выбрать для бизнеса в Казахстане и как запустить приложение правильно.

OWASP Top 10 2025: безопасность веб-приложений для казахстанского разработчикаaunimeda
Разработка

OWASP Top 10 2025: безопасность веб-приложений для казахстанского разработчика

OWASP Top 10 — это стандарт критических рисков безопасности. SQL-инъекции, сломанный контроль доступа, SSRF — каждый пункт с реальной атакой на ваш Node.js/Next.js код и конкретным исправлением. Актуально для проектов на казахстанском рынке.

Node.js vs Bun vs Deno 2026: бенчмарки и выбор runtime для продакшнaunimeda
Разработка

Node.js vs Bun vs Deno 2026: бенчмарки и выбор runtime для продакшн

Bun 1.x стабилен в production. Deno 2.0 поддерживает npm-пакеты. Node.js 22 запускает TypeScript нативно. Реальные бенчмарки производительности, сравнение инструментов и конкретные рекомендации для казахстанских разработчиков.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Казахстане. Бесплатная консультация.

Получить консультацию Все статьи