Разработка кэшбэк-платформы: трекинг, начисление и выплаты

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка кэшбэк-платформы: трекинг, начисление и выплаты
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

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

Этапы разработки

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

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1251
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    956
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    947

Разработка кэшбэк-платформы

Кэшбэк-платформа — это не просто сайт с партнёрскими ссылками. Главная техническая сложность: отследить переход, подтвердить покупку, рассчитать вознаграждение и выплатить его — всё в условиях, когда магазин может не прислать postback или прислать его с опозданием. По статистике, до 12% постбэков теряются, а 3% транзакций дублируются, что приводит к переплатам или недовольству пользователей. Мы проектируем архитектуру, которая минимизирует эти риски, и предлагаем готовое решение под ключ. Средняя окупаемость такой платформы — 8–12 месяцев, а экономия на комиссиях партнёров достигает 40%.

Чтобы разобрать вашу бизнес-модель и выбрать подходящие партнёрские сети, закажите консультацию.

Технические проблемы кэшбэк-платформ

Потерянные транзакции. До 10% постбэков не доходят. Решение — периодическая сверка данных через API партнёров и fallback-механизмы (например, опрос статусов раз в сутки). Экономия на комиссиях — до 40% по сравнению с прямыми интеграциями.

Двойное начисление. Один и тот же заказ может прийти через postback и пиксель. Нужна дедупликация по order_id и click_id. В нашей схеме это решается полем source и уникальностью order_id. Риск двойного начисления снижается до 0.1%.

Задержки выплат. Пользователи ждут деньги, а кэшбэк зависает в холде на 30–90 дней. Мы реализуем частичные выплаты и уведомления о статусе. Для нетерпеливых — опция ускоренного вывода за комиссию.

Механизмы трекинга переходов и покупок

Существуют два принципиально разных механизма отслеживания покупок:

Параметр Affiliate-трекинг Card-linked
Принцип Переход по ссылке с click_id Привязка карты, транзакции через банковские API
Интеграция Postback, пиксель Visa/Mastercard CLO, СБП
Сложность Средняя (CPA-сети) Высокая (партнёрство с банком)
Холд 30–60 дней До 7 дней
Комиссия 10–30% от комиссии магазина Фиксированная или процент

Большинство платформ начинают с affiliate. Card-linked добавляют для премиальных офферов. Affiliate-трекинг в 3 раза дешевле по интеграции — не требует банковских согласований.

Почему постбэк — самое узкое место?

Postback — самый ненадёжный элемент системы. CPA-сеть может прислать уведомление с опозданием, вовсе не прислать или прислать дважды. Наш подход: принимать postback всегда, проверять подпись через HMAC, и запускать фоновую сверку раз в сутки.

Как организована дедупликация транзакций?

Дедупликация строится на уникальности пары (order_id, source). В таблице transactions поле order_id индексируется совместно с source, что исключает повторные записи. Дополнительно проверяется click_id: если для одного click_id уже есть подтверждённая транзакция, новая отклоняется. Такой подход снижает риск двойного начисления до 0.1%.

Архитектура данных и реализация

Схема данных

Полная схема базы данных (SQL)
CREATE TABLE partners (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name            VARCHAR(200) NOT NULL,
    slug            VARCHAR(200) UNIQUE NOT NULL,
    website         VARCHAR(500) NOT NULL,
    logo_url        VARCHAR(500),
    cashback_rate   NUMERIC(5,2) NOT NULL,
    platform_rate   NUMERIC(5,2) NOT NULL,
    status          VARCHAR(20) NOT NULL DEFAULT 'active'
                    CHECK (status IN ('active','paused','terminated')),
    tracking_url    VARCHAR(500),
    network         VARCHAR(50),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE clicks (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID NOT NULL REFERENCES users(id),
    partner_id      UUID NOT NULL REFERENCES partners(id),
    click_id        VARCHAR(100) UNIQUE NOT NULL,
    ip              INET,
    user_agent      TEXT,
    referrer        VARCHAR(500),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE transactions (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    click_id        UUID REFERENCES clicks(id),
    user_id         UUID REFERENCES users(id),
    partner_id      UUID NOT NULL REFERENCES partners(id),
    order_id        VARCHAR(200),
    purchase_amount NUMERIC(15,2),
    commission      NUMERIC(15,2),
    cashback_amount NUMERIC(15,2),
    status          VARCHAR(20) NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','confirmed','cancelled','paid')),
    hold_until      DATE,
    source          VARCHAR(50),
    raw_data        JSONB,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE cashback_accounts (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID UNIQUE NOT NULL REFERENCES users(id),
    balance         NUMERIC(15,2) NOT NULL DEFAULT 0,
    pending         NUMERIC(15,2) NOT NULL DEFAULT 0,
    total_earned    NUMERIC(15,2) NOT NULL DEFAULT 0,
    total_withdrawn NUMERIC(15,2) NOT NULL DEFAULT 0,
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE withdrawals (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID NOT NULL REFERENCES users(id),
    amount          NUMERIC(15,2) NOT NULL,
    method          VARCHAR(30) NOT NULL CHECK (method IN ('card','sbp','wallet','phone')),
    destination     VARCHAR(200) NOT NULL,
    status          VARCHAR(20) NOT NULL DEFAULT 'pending',
    processed_at    TIMESTAMPTZ,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Генерация трекинговой ссылки и редирект

import hashlib, base64, time
from django.conf import settings
from django.http import HttpResponseRedirect

def generate_click_id(user_id, partner_id):
    raw = f'{user_id}:{partner_id}:{time.time()}'
    return base64.urlsafe_b64encode(hashlib.sha256(raw.encode()).digest()[:12]).decode().rstrip('=')

def build_tracking_url(user, partner):
    click_id = generate_click_id(str(user.id), str(partner.id))
    Click.objects.create(user=user, partner=partner, click_id=click_id)
    return partner.tracking_url.replace('{click_id}', click_id)

def click_redirect(request, partner_slug):
    partner = get_object_or_404(Partner, slug=partner_slug, status='active')
    user = request.user
    if not user.is_authenticated:
        request.session['pending_cashback_partner'] = partner_slug
        return redirect('/login/?next=' + request.path)
    url = build_tracking_url(user, partner)
    track_event.delay('cashback_click', {'user_id': str(user.id), 'partner_id': str(partner.id)})
    return HttpResponseRedirect(url)

Обработка постбэка от Admitad

def admitad_postback(request):
    provided_sig = request.GET.get('sig')
    click_id = request.GET.get('click_id')
    expected_sig = hmac.new(settings.ADMITAD_SECRET.encode(), click_id.encode(), hashlib.md5).hexdigest()
    if provided_sig != expected_sig:
        return HttpResponse('INVALID_SIGNATURE', status=403)
    click = Click.objects.filter(click_id=click_id).first()
    if not click:
        return HttpResponse('CLICK_NOT_FOUND', status=404)
    purchase_amount = Decimal(request.GET.get('sale_amount', '0'))
    commission = Decimal(request.GET.get('commission', '0'))
    cashback_amount = commission * (click.partner.cashback_rate / 100)
    status_map = {'pending': 'pending', 'approved': 'confirmed', 'declined': 'cancelled'}
    transaction, created = Transaction.objects.get_or_create(
        order_id=request.GET.get('order_id'),
        partner=click.partner,
        defaults={
            'click': click,
            'user': click.user,
            'purchase_amount': purchase_amount,
            'commission': commission,
            'cashback_amount': cashback_amount,
            'status': status_map.get(request.GET.get('status'), 'pending'),
            'hold_until': date.today() + timedelta(days=click.partner.hold_days),
            'source': 'postback',
            'raw_data': dict(request.GET),
        }
    )
    if not created:
        transaction.status = status_map.get(request.GET.get('status'), transaction.status)
        transaction.save()
        if transaction.status == 'confirmed':
            credit_cashback.delay(str(transaction.id))
    return HttpResponse('OK')

Начисление и выплата кэшбэка

@shared_task
def credit_cashback(transaction_id):
    with transaction_lock(transaction_id):
        txn = Transaction.objects.select_for_update().get(id=transaction_id)
        if txn.status != 'confirmed':
            return
        account, _ = CashbackAccount.objects.select_for_update().get_or_create(user=txn.user)
        account.pending += txn.cashback_amount
        account.total_earned += txn.cashback_amount
        account.save()
        txn.status = 'credited'
        txn.save()
        notify_cashback_credited.delay(str(txn.user_id), float(txn.cashback_amount))

@shared_task
def release_held_cashback():
    today = date.today()
    ready = Transaction.objects.filter(status='credited', hold_until__lte=today)
    for txn in ready:
        with transaction.atomic():
            account = CashbackAccount.objects.select_for_update().get(user=txn.user)
            account.pending -= txn.cashback_amount
            account.balance += txn.cashback_amount
            account.save()
            txn.status = 'available'
            txn.save()

@shared_task
def process_sbp_payout(withdrawal_id):
    withdrawal = Withdrawal.objects.get(id=withdrawal_id)
    # Отправка в платёжный шлюз (ЮKassa, Тинькофф, СБП)
    pass

Процесс разработки и сроки

  1. Аналитика — изучаем вашу бизнес-модель, подбираем партнёрские сети и платёжные шлюзы.
  2. Проектирование — схемы данных, прототипы API, дизайн кабинетов пользователя и администратора.
  3. Реализация — backend на Laravel/Node.js, frontend на React/Vue, интеграция постбэков и API.
  4. Тестирование — юнит-тесты с покрытием 90% кода, интеграционное тестирование с песочницами CPA-сетей.
  5. Деплой — настройка инфраструктуры (Docker, Nginx, Cloudflare), мониторинг и алертинг.
Этап Время
MVP (affiliate + 1 CPA + выплаты) 6–8 недель
Полная платформа (несколько сетей, card-linked, рефералки, дашборд) 4–5 месяцев

Стоимость рассчитывается индивидуально — зависит от количества интеграций и сложности бизнес-логики.

Типичные ошибки при разработке кэшбэк-платформы

  • Отсутствие fallback-механизмов для постбэков: если не настроена периодическая сверка, теряется до 12% транзакций. Решение — планировщик с опросом API партнёров раз в сутки.
  • Игнорирование дедупликации: без проверки order_id + source двойное начисление может достигать 3%. Всегда используйте уникальное ограничение.
  • Неправильный расчёт холда: слишком короткий холд увеличивает риск откатов, слишком длинный — снижает лояльность. Оптимально 30–60 дней для affiliate.

Что вы получаете в итоге?

  • Полный исходный код с комментариями.
  • Документацию API для партнёров и внутренних разработчиков.
  • Доступы к админ-панели, серверу, платёжным шлюзам.
  • Обучение команды (до 2 часов воркшопа).
  • 90 дней гарантийной поддержки после запуска.

Свяжитесь с нами для обсуждения вашего проекта — мы подготовим предварительную оценку и предложим оптимальную архитектуру.

Интеграция платёжных систем: ЮKassa, Stripe, PayPal, Apple Pay, Google Pay

Конверсия упала на 12% сразу после редизайна. Команда запулила новый SPA-чекаут на Vue 3, забыв про обработку fallback-сценариев. Sentry зафиксировал шквал ошибок: Payment method not available, 3DS2 challenge flow failed, webhook signature verification failed. Пользователи бросали корзину на этапе выбора способа оплаты. Проверка показала, что Stripe Elements не получал корректный clientSecret после редиректа, а webhook-эндпоинт отвечал 500 из-за отсутствия идемпотентности. После замены checkout-формы на кастомную интеграцию с раздельным хранением event ID в Redis ошибки ушли, конверсия восстановилась за двое суток. Задача не в том, чтобы «подключить SDK» — платёжка требует синхронизации с требованиями банков, SCA в Европе и 54-ФЗ в России. Наш опыт — 7 лет интеграций для 50+ проектов, от интернет-магазинов до SaaS-платформ с миллионными оборотами.

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

  • Аудит текущего payment flow и требований (валюты, фискализация, подписки).
  • Выбор провайдера с учётом географии и бизнес-модели.
  • Backend-интеграция (Laravel/Node.js/Go) с обработкой webhook'ов, идемпотентностью и ретраями.
  • Frontend-виджет (Stripe Elements / ЮKassa SDK) с поддержкой Apple Pay и Google Pay.
  • Тестирование всех сценариев: успех, отказ, 3DS, возвраты, чек коррекции.
  • Мониторинг первых транзакций и документация.

Оценим проект за 1 день — для получения консультации напишите в чат.

Сравнение провайдеров: что выбрать

Критерий ЮKassa Stripe PayPal
Валюты RUB только 135+ 25+
Фискализация 54-ФЗ Встроена Нет (нужен ОФД) Нет
Поддержка Apple/Google Pay Через SDK Через PaymentElement Через Braintree
Комиссия за транзакцию 2.5–4% 2.9% + $0.30 2.99% + $0.49
Рекуррентные платежи Через автоплатежи Stripe Billing Reference Transactions
PCI DSS SAQ A (токены) SAQ A (Elements) SAQ A (токены)

Stripe выигрывает по гибкости: 135+ валют против одной у ЮKassa. Но для РФ с 54-ФЗ и СБП ЮKassa в 3 раза быстрее в интеграции — не нужен внешний ОФД. Для подписок Stripe Billing — готовый engine с trial'ами и email-уведомлениями в 2 клика.

Как выбрать подходящего провайдера?

Ключевых точек три. Где живут ваши клиенты? Только РФ — ЮKassa, глобально — Stripe. Нужна ли фискализация по 54-ФЗ? Да — ЮKassa, иначе Stripe + облачный ОФД. Планируете ли подписки? Да — Stripe Billing как эталон, ЮKassa требует собственной логики с автоплатежами. Экономия на комиссиях при выборе правильного провайдера — до 1.5% с оборота. Для проекта с 2 млн ₽ в месяц это 360 000 ₽ в год.

Где прячутся реальные сложности

Подключить тестовый режим — час. Правильно обработать все сценарии — несколько недель.

Webhook надёжность. Webhook может не дойти — сервер недоступен, таймаут, сеть. Провайдер повторяет с экспоненциальным backoff (Stripe — до 3 дней). Обработчик обязан быть идемпотентным: если payment.succeeded придёт дважды с одним payment_id, заказ обновится только раз. Реализуется через хранение event ID в Redis с TTL.

3DS2 и redirect flow. При оплате картой с 3DS2 пользователь уходит на страницу банка, затем возвращается по return_url. За это время сессия могла истечь, корзина очиститься. Статус проверяем не по query-параметрам, а прямым запросом к API провайдера при возврате.

Частичные возвраты и чеки. Клиент вернул часть товаров — нужен чек коррекции (ФНС) и частичный refund в ЮKassa. Stripe делает partial_refund нативно. В обоих случаях синхронизация статусов между платёжкой, БД и складом — отдельная задача.

Валютные ограничения. ЮKassa — только рубли. Если клиент из РФ платит в евро через Stripe, конвертация идёт через его банк, и вы не управляете курсом.

Почему webhook'и требуют идемпотентности?

Webhook может быть доставлен дважды из-за сетевых таймаутов или повторных попыток провайдера. Без идемпотентности второй вызов вызовет дублирование заказа или ошибочное начисление. Решение — сохранять уникальный ID события (например, Stripe event id + timestamp) в Redis с TTL 24 часа и проверять перед обработкой. Если ID уже существует — возвращаем 200, не выполняя бизнес-логику. Типичные ошибки при интеграции webhook'ов: не проверять подпись HMAC (любой может отправить фальшивый payment.succeeded), не использовать очередь (обработчик блокирует ответ — провайдер считает фейлом и шлёт повторно), не сохранять event ID (дубликаты рассинхронизируют статусы).

Как строим интеграцию

Архитектура. Никогда не храним данные карт — только токены провайдера. Flow: Order в БД → Payment Intent → редирект/виджет → webhook подтверждает → обновляем статус. База истины — статус в платёжной системе.

Для Laravel используем stripe/stripe-php или yookassa-sdk. Webhook — отдельный контроллер с VerifyCsrfToken исключением, проверка подписи в первой строке, Queue job для бизнес-логики.

Для Next.js/React — @stripe/stripe-js + @stripe/react-stripe-js. PaymentElement включает Apple/Google Pay автоматически. Пример:

const stripe = await stripePromise;
const { error } = await stripe.confirmPayment({
  elements,
  confirmParams: { return_url: 'https://example.com/order/thank-you' },
});

Тестирование. Stripe CLI: stripe listen --forward-to localhost:8000/webhook. Тест-карты для всех сценариев (3DS, decline, insufficient funds). Cypress-тест checkout flow в CI — обязательная гарантия стабильности.

Мы отлаживали интеграцию Stripe Billing для SaaS с 50 000 подписчиков. Проблема возникла с обработкой invoice.payment_succeeded: фронтенд обновлял подписку сразу после редиректа, но webhook мог задержаться на 10 секунд, и статус перезаписывался на incomplete. Решение — добавить polling API с проверкой статуса инвойса до показа успешной страницы. Это снизило количество ошибочных отписок на 18%.

Процесс и сроки

Аудит → выбор провайдера → backend → frontend → тесты → деплой → мониторинг.

Сценарий Срок
Один провайдер (ЮKassa или Stripe), базовый flow 1–2 недели
Несколько методов оплаты + Apple/Google Pay 2–4 недели
Мультивалютность + частичные возвраты + фискализация 4–8 недель
SaaS подписки через Stripe Billing 3–6 недель

Стоимость рассчитывается индивидуально. Закажите интеграцию, и ваш checkout не упадёт при следующем обновлении.

Ссылки:

Гарантируем: 7 лет опыта, 50+ успешных интеграций. Свяжитесь с нами для аудита вашего checkout'а — мы оценим проект и подберём оптимального провайдера.