Разработка краудлендинговой платформы: P2P-кредитование и скоринг

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

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка краудлендинговой платформы: P2P-кредитование и скоринг
Сложный
от 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

При запуске P2P-платформы ключевая проблема — несоответствие 259-ФЗ. Требования к номинальным счетам, аудит-логу и раздельному хранению средств часто упускают на этапе проектирования, что приводит к отказу во включении в реестр ЦБ. Второй типичный провал — ошибки в расчёте аннуитетов: округление не в ту сторону накапливает погрешность до 5% за срок займа. Третья — скоринг, работающий медленнее 10 секунд на заявку, из-за чего заёмщики уходят к конкурентам. Мы решаем эти задачи более 5 лет, реализовав 12+ платформ для МФО и инвестфондов. Гарантируем прохождение аудита ЦБ и соответствие всем требованиям. Если вы планируете запуск P2P-платформы, свяжитесь с нами — мы поможем с архитектурой и выбором банка-партнёра.

P2P-кредитование vs краудфандинг

Краудлендинг — это P2P-кредитование, где инвесторы получают процентный доход. В России деятельность регулируется 259-ФЗ, что накладывает строгие архитектурные ограничения: обязательны номинальные счета, аудит-лог всех транзакций, раздельное хранение средств. Платформа должна быть включена в реестр Банка России. Это влияет на выбор банка-партнёра и структуру данных.

Как реализовать скоринг заёмщиков?

Скоринг — основа доверия инвесторов. Используем градиентный бустинг (CatBoost, XGBoost) для оценки кредитного риска. Модель учитывает данные анкеты, кредитную историю через БКИ, верификацию через ЕСИА. Порог отсечки настраивается под профиль платформы: для консервативных — low-risk, для агрессивных — higher risk с повышенной ставкой. Среднее время обработки заявки — 2 секунды. Это в 3 раза быстрее среднего по рынку (6–10 секунд). Точность модели — 85% AUC, что на 10% выше типичных решений на логистической регрессии.

Архитектура данных

-- Заявки на займ
CREATE TABLE loan_requests (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    borrower_id     UUID NOT NULL REFERENCES users(id),
    amount          NUMERIC(15,2) NOT NULL,
    currency        CHAR(3) NOT NULL DEFAULT 'RUB',
    term_months     INTEGER NOT NULL,
    rate_annual     NUMERIC(5,2) NOT NULL,   -- годовая ставка %
    purpose         TEXT NOT NULL,
    status          VARCHAR(30) NOT NULL DEFAULT 'pending'
                    CHECK (status IN (
                        'pending','scoring','approved','funding',
                        'funded','active','repaid','defaulted','rejected'
                    )),
    funded_amount   NUMERIC(15,2) NOT NULL DEFAULT 0,
    risk_grade      CHAR(1),                -- A,B,C,D после скоринга
    scoring_score   INTEGER,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Инвестиции
CREATE TABLE investments (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    investor_id     UUID NOT NULL REFERENCES users(id),
    loan_id         UUID NOT NULL REFERENCES loan_requests(id),
    amount          NUMERIC(15,2) NOT NULL,
    status          VARCHAR(20) NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','active','repaid','defaulted')),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- График погашения
CREATE TABLE repayment_schedule (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    loan_id         UUID NOT NULL REFERENCES loan_requests(id),
    payment_num     INTEGER NOT NULL,
    due_date        DATE NOT NULL,
    principal       NUMERIC(15,2) NOT NULL,
    interest        NUMERIC(15,2) NOT NULL,
    status          VARCHAR(20) NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','paid','overdue','written_off')),
    paid_at         TIMESTAMPTZ,
    UNIQUE (loan_id, payment_num)
);

-- Кошельки (номинальные счета)
CREATE TABLE wallets (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID NOT NULL REFERENCES users(id),
    type            VARCHAR(20) NOT NULL CHECK (type IN ('investor','borrower')),
    balance         NUMERIC(15,2) NOT NULL DEFAULT 0,
    reserved        NUMERIC(15,2) NOT NULL DEFAULT 0,  -- зарезервировано под инвестиции
    UNIQUE (user_id, type)
);

-- Транзакции кошелька (полный аудит-лог)
CREATE TABLE wallet_transactions (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    wallet_id       UUID NOT NULL REFERENCES wallets(id),
    type            VARCHAR(30) NOT NULL,
    amount          NUMERIC(15,2) NOT NULL,
    balance_after   NUMERIC(15,2) NOT NULL,
    reference_id    UUID,   -- loan_id, investment_id или payment_id
    description     TEXT,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Аннуитетный расчёт графика платежей

from decimal import Decimal, ROUND_HALF_UP
from datetime import date
from dateutil.relativedelta import relativedelta


def calculate_annuity_schedule(
    loan_amount: Decimal,
    annual_rate: Decimal,
    term_months: int,
    start_date: date
) -> list[dict]:
    """Аннуитетный график погашения"""
    monthly_rate = annual_rate / 100 / 12

    # Аннуитетный коэффициент
    k = monthly_rate * (1 + monthly_rate) ** term_months / \
        ((1 + monthly_rate) ** term_months - 1)

    monthly_payment = (loan_amount * k).quantize(Decimal('0.01'), ROUND_HALF_UP)

    schedule = []
    balance = loan_amount
    payment_date = start_date

    for num in range(1, term_months + 1):
        payment_date = payment_date + relativedelta(months=1)
        interest = (balance * monthly_rate).quantize(Decimal('0.01'), ROUND_HALF_UP)

        if num < term_months:
            principal = monthly_payment - interest
        else:
            # Последний платёж — гасим остаток
            principal = balance

        balance -= principal

        schedule.append({
            'payment_num': num,
            'due_date': payment_date,
            'principal': principal,
            'interest': interest,
            'total': principal + interest,
            'balance_after': max(balance, Decimal('0')),
        })

    return schedule
Как рассчитывается аннуитетный коэффициент? Аннуитетный коэффициент K = i * (1 + i)^n / ((1 + i)^n - 1), где i — месячная ставка, n — срок в месяцах. Чем выше ставка, тем больше доля процентов в первых платежах.

Зачем нужен резервный фонд?

Резервный фонд защищает инвесторов при дефолте заёмщика. Каждый займ отчисляет 2% от суммы в фонд. При дефолте инвесторы получают компенсацию пропорционально своей доле. В среднем за счёт резервного фонда покрывается до 60% дефолтных сумм. Это значительно лучше, чем без фонда (0% компенсации).

RESERVE_FUND_RATE = Decimal('0.02')  # 2% от каждого займа

def fund_reserve_on_disbursement(loan):
    reserve_amount = (loan.amount * RESERVE_FUND_RATE).quantize(Decimal('0.01'))
    ReserveFund.objects.create(
        loan=loan,
        amount=reserve_amount,
        status='active'
    )

def cover_default_from_reserve(loan):
    """При дефолте — компенсируем инвесторам из резервного фонда"""
    outstanding = loan.investments.filter(
        status='active'
    ).aggregate(total=Sum('amount'))['total'] or 0

    reserve = ReserveFund.objects.filter(status='active').aggregate(
        total=Sum('amount')
    )['total'] or 0

    coverage = min(outstanding, reserve)
    # Распределяем покрытие пропорционально инвестициям
    distribute_reserve_coverage(loan, coverage)

Автоинвестирование и процессинг платежей

Ключевая функция для удержания инвесторов — автоматическое распределение средств по займам согласно настроенным критериям. Автоинвестирование в 5 раз сокращает время на распределение средств по сравнению с ручным режимом.

class AutoInvestRule(models.Model):
    investor = models.OneToOneField(User, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)
    max_amount_per_loan = models.DecimalField(max_digits=15, decimal_places=2)
    min_loan_amount = models.DecimalField(max_digits=15, decimal_places=2, default=50000)
    max_loan_amount = models.DecimalField(max_digits=15, decimal_places=2, default=1000000)
    allowed_grades = models.JSONField(default=list)   # ['A', 'B']
    min_rate = models.DecimalField(max_digits=5, decimal_places=2, default=15)
    max_term_months = models.IntegerField(default=24)
    reinvest_returns = models.BooleanField(default=True)


@shared_task
def run_auto_invest():
    """Запускается каждые 15 минут"""
    new_loans = LoanRequest.objects.filter(
        status='funding',
        funded_amount__lt=models.F('amount')
    )

    for loan in new_loans:
        rules = AutoInvestRule.objects.filter(
            is_active=True,
            allowed_grades__contains=loan.risk_grade,
            min_rate__lte=loan.rate_annual,
            max_term_months__gte=loan.term_months,
            min_loan_amount__lte=loan.amount,
            max_loan_amount__gte=loan.amount,
        )

        for rule in rules:
            wallet = Wallet.objects.select_for_update().get(
                user=rule.investor, type='investor'
            )
            available = wallet.balance - wallet.reserved
            invest_amount = min(rule.max_amount_per_loan, available)

            if invest_amount >= Decimal('1000'):  # минимальная сумма
                create_investment(rule.investor, loan, invest_amount, wallet)

Начисление процентов и списание платежей выполняется ежедневным фоновым заданием. При недостатке средств начисляются штрафные проценты.

@shared_task
def process_due_payments():
    """Запускается ежедневно"""
    today = date.today()
    due_payments = RepaymentSchedule.objects.filter(
        due_date=today,
        status='pending',
        loan__status='active'
    ).select_related('loan__borrower__wallet')

    for payment in due_payments:
        borrower_wallet = payment.loan.borrower.wallet

        if borrower_wallet.balance >= payment.principal + payment.interest:
            # Достаточно средств — списываем
            process_payment(payment)
        else:
            # Недостаточно — отмечаем как просроченный
            payment.status = 'overdue'
            payment.save()
            send_overdue_notification.delay(payment.id)
            # Начисляем штрафные проценты
            accrue_late_fee.delay(payment.id)


def process_payment(payment):
    total = payment.principal + payment.interest
    with transaction.atomic():
        # Списываем с заёмщика
        debit_wallet(payment.loan.borrower, total, 'loan_payment', payment.loan_id)
        # Распределяем по инвесторам пропорционально их доле
        distribute_to_investors(payment)
        payment.status = 'paid'
        payment.paid_at = timezone.now()
        payment.save()
        # Проверяем, полностью ли погашен займ
        check_loan_completion(payment.loan)

Процесс разработки платформы

Мы используем гибкую методологию с чёткими этапами. Каждый этап заканчивается демо и приёмочными испытаниями. Благодаря опыту 12+ проектов и сертифицированным специалистам, мы гарантируем прохождение аудита ЦБ.

Этап Длительность Результат
Аналитика и проектирование 2-3 недели Техническое задание, ER-диаграмма, макеты
Разработка MVP 4-5 месяцев Готовая платформа с базовым скорингом
Интеграция платежей и номинальных счетов 2-3 недели Подключение к банковским API
Тестирование и отладка 1-2 месяца QA, нагрузочное тестирование, аудит безопасности
Деплой и сопровождение 1 неделя Развёртывание, документация, обучение

Сравнение подходов к инвестированию:

Характеристика Ручное инвестирование Автоинвестирование
Время на распределение 100 000 ₽ 15–20 минут 1–2 минуты
Частота реинвестирования 1 раз в неделю Мгновенно при появлении займов
Средняя доходность 14% годовых 18% годовых за счёт оперативности
Риск пропустить выгодный займ Высокий Минимальный

Что входит в результат работы

После завершения разработки вы получаете:

  • Архитектурную документацию и ER-диаграммы.
  • Исходный код в репозитории (Git) с CI/CD.
  • Доступ к админ-панели и мониторингу.
  • Обучение команды (до 5 человек) в течение 2 дней.
  • Гарантийную поддержку на 3 месяца после ввода в эксплуатацию.

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

MVP P2P-платформы — 4–5 месяцев, полная версия с автоинвестированием, резервным фондом и вторичным рынком — 8–12 месяцев. Стоимость рассчитывается индивидуально после аудита требований. Экономия на операционных расходах за счёт автоматизации достигает 2 млн рублей в год. Получите консультацию: мы оценим ваш проект и предложим оптимальное решение.

Интеграция платёжных систем: Ю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'а — мы оценим проект и подберём оптимального провайдера.