Приём платежей на сайте без ИП и договора

Подключить платёжную систему к сайту непросто. Даже не в плане реализации, а из за бюрократии. Для работы с платежным агрегатором нужно быть индивидуальным предпринимателем и заключать договор.

Однако, у нас тут тривиальная задача для небольшого сервиса: за денежку открывать пользователю дополнительные плюшки. Сервис настолько небольшой, что даже не покроет затраты на содержание ИП.

Яндекс.Деньги умеют отправлять HTTP-уведомления о входящих платежах на сайт. То есть как только на кошелёк поступает платёж, сервер Яндекса отправляет данные о платеже на указанный URL.

Яндекс.Деньги HTTP-уведомления

И никакой тебе бюрократии. Нужно просто на своей стороне принимать уведомления от Яндекс.Денег, как это описано в документация. Попробуем.

Оплата

Чтобы инициировать платёж, нужно редиректнуть пользователя на страницу https://money.yandex.ru/quickpay/confirm.xml и передать в GET или POST параметрах счёт получателя, сумму и прочее.

receiver = "4100..."
quickpayform = "shop"
successURL = "http://example.com/billing/success"
formcomment = "Мой магазин: Валенки белые"
shortdest = "Мой магазин: Валенки белые"
targets = "Оплата заказа"
paymentType = "PC"
sum = "499"
label = "12345"

Подробное описание полей есть в документации. Обратите внимание на поле label — в него нужно положить id заказа, который придёт обратно в уведомлении, после отплаты.

Кстати, у Денег есть конструктор таких форм, но он сильно ограничен в вопросах кастомизации, поэтому я рекомендую его пропустить и запилить свою форму на основе примера выше.

Обработка уведомлений

Когда пользователь совершит платёж, на указанный в настройках адрес Яндекс отправит обыкновенный POST запрос со следующим набором полей.

sha1_hash = "ac13833bd6ba9eff1fa9e4bed76f3d6ebb57f6c0"
operation_id = "441361714955017004"
notification_type = "card-incoming"
datetime = "2013-12-26T08:28:34Z"
sender = ""
codepro = "false"
currency = "643"
amount = "497"
withdraw_amount = "499"
label = "12345"

Здесь нас интересует поле label. Из него надо взять номер заказа, найти его в базе данных и отметить оплаченным. А еще проверить, что сумма в уведомлении соответствует сумме заказа.

order = Order.objects.get(id=form_data['label'])
if float(form_data['withdraw_amount']) < order.amount:
    return HttpResponse('INVALID_AMOUNT', status=400)

order.mark_paid()
return HttpResponse()

Если у вас несколько сайтов, которые принимают платежи на один кошелёк, можно сделать промежуточный сервис, который будет проксировать запросы к этим сайтам в зависимости от префикса поле label.

Такой вот простой приём платежей. Я опустил реализацию проверки подлинности, чтобы не засорять статью кодом. Код реализации на Питоне можно найти в этом гисте.