Х20 - это новый XML-интерфейс WebMoney, который работает на той же платформе, что и WebMoney Merchant и интерфейс Х18. Он обращается к тому же серверу merchant.webmoney.ru и использует те же принципы аутентификации на базе SecretKey и торговых кошельков. Х20 позволяет принимать оплату БЕЗ отправки юзера на сайт merchant.webmoney.ru в браузере. Поэтому Х20 - это идеальный способ принимать WM-платежи там, где открытие и использование браузера нежелательно или невозможно. Например, в мобильных приложениях, Windows-программах. Тем не менее, для простоты и наглядности, мы будем демонстировать работу Х20 именно в браузере здесь. Программный код мы реализуем на PHP и включим соответствующую функцию _WMXML20() в библитеку XOWM, которую оВебМани.Ру давно поддерживает и дополняет. Использовать Х20 может любой торговец - владелец кошелька, настроенного на работу с WM Merchant. Статью о том, как работает этот сервис и как его использовать, можно прочесть здесь на owebmoney.ru. Как работает Х20 Этот интерфейс - единственный из существующих, который работает 2-тактно. Иными словами, он совмещает в себе 2 запроса, которые нужно отправлять последовательно, при этом второй без первого существовать не может. Как работает Х20 детально описано на wiki. Читать обязательно! Однако, оВебМани.Ру для того и нужен, чтобы расжевать всё и разложить по полочкам Поэтому вернитесь сюда, когда дочитаете статью на wiki. Х20 работает так: 1-й запрос, инициирование оплаты В 1-м запросе вы передаете: идентификатор плательщика - email, либо телефон, либо WMID; желаемый способ подтверждения платежа - SMS или USSD. другие параметры будущего платежа, например, сумму (это очень похоже на "форму запроса платежа" в классическом протоколе WM Merchant). Исходя из идентификатора юзера и желаемого способа подтверждения, сервер WebMoney определяет недостающую информацию. Например, если вы сообщили: "email юзера такой-то, а подтвердить оплату он хочет по SMS", то сервер WebMoney по email отыщет его WMID и телефон, после чего отправит на телефон SMS с кодом подтверждения. Независимо от того, какой способ подтверждения выбран - SMS или USSD - сервер WebMoney всегда дополнительно выписывает WM-счет. Юзер на выбор может либо подтвердить оплату по SMS\USSD, либо оплатить WM-счет в своем Кипере (а оплачивать счета - напомним - позволяет абсолютно любая версия Кипера: Классик, Лайт, Мини и Мобайл). При подтверждении по SMS\USSD сервер WebMoney списывает оплату с первого попавшегося кошелька юзера (если внутри его WMID есть несколько кошельков), на котором достаточно денег. Таблица ниже демонстрирует, что происходит на сервере WebMoney в зависимости от тех или иных входных данных: При нахождении WMID по email, WMID по телефону, телефона по WMID и т.п. - используются email и телефон, которые указаны в аттестате. Кроме того, X20 учитывает телефоны, зарегистрированные в WebMoney Чек. Если в запросе будет передан телефон, который зарегистрирован в WebMoney Чек и не зарегистрирован ни в одном аттестате, то оплата спишется именно с Чека. При этом, конечно, WM-счет выписан не будет, т.к. Чек не поддерживает оплату счетов. Если вы обратите внимание на последнюю строчку таблицы, то увидите, что Х20 позволяет просто выписать юзеру WM-счет, не отправляя SMS или USSD. А значит, Х20 - это простая и удобная замена совместному использованию интерфейсов X1 + X4. Мы говорим "простая", потому что в Х1 и Х4 обязательно нужно применять WMSigner для подписи запросов, а в X20 - не обязательно. В ответ на 1-й запрос WebMoney отдает вам уникальный номер счета. 2-й запрос, подтверждение оплаты Вызов 2-го запроса разумно возложить на самого юзера, например, показать ему кнопку типа "я подтверждаю оплату". Во 2-м запросе вы передаете: номер счета, который получен в 1-м запросе; если подтверждение по SMS, то юзер должен ввести у вас на сайте (в программе, в приложении) SMS-код, который он получил от WebMoney, а вы должны передать этот SMS-код. Получив от вас 2-й запрос, сервер WebMoney: Проверяет, а не оплачен ли уже данный счет. Это логично, потому что после отработки 1-го запроса до вызова 2-го могло пройти время, в течение которого юзер мог подтвердить оплату, например, через USSD (если, конечно, было заказано подтверждение по USSD), либо путем оплаты WM-счета в Кипере. Если подтверждение по SMS, то проверяется корректность SMS-кода, который вы передали в запросе, и если он корректен, то тут же происходит списание денег с кошелька юзера и сервер WebMoney рапортует вам о том, что оплата успешно произведена. 1-й запрос Как мы уже знаем, 1-й запрос инициирует оплату. Отправляется на URL https://merchant.webmoney.ru/conf/xml/XMLTransRequest.asp методом POST. Состав запроса: Code: <merchant.request> <wmid></wmid> <lmi_payee_purse></lmi_payee_purse> <lmi_payment_no></lmi_payment_no> <lmi_payment_amount></lmi_payment_amount> <lmi_payment_desc></lmi_payment_desc> <lmi_clientnumber></lmi_clientnumber> <lmi_clientnumber_type></lmi_clientnumber_type> <lmi_sms_type></lmi_sms_type> <secret_key></secret_key> <sign></sign> <md5></md5> </merchant.request> wmid - ваш WMID, подключенный к WM Merchant. lmi_payee_purse - ваш торговый кошелек (в рамках wmid), подключенный к WM Merchant. lmi_payment_no - номер платежа в вашей учетной системе (аналог LMI_PAYMENT_NO в "форме запроса платежа" WM Merchant). Можно оставлять пустым, но лучше все-таки назначать и, более того, лучше делать его уникальным. lmi_payment_amount - сумма в валюте кошелька (аналог LMI_PAYMENT_AMOUNT в "форме запроса платежа" WM Merchant), разделитель дробной части - точка. lmi_payment_desc - описание покупки (аналог LMI_PAYMENT_DESC в "форме запроса платежа" WM Merchant). Внимание! В отличие от WM Merchant, где этот параметр передается в Win1251, здесь его нужно передавать в UTF8. lmi_clientnumber - идентификатор юзера: номер телефона (без знака "+"), либо email, либо WMID. lmi_clientnumber_type - указатель, что именно было передано в lmi_clientnumber (0 - телефон; 1 - WMID; 2 - email). lmi_sms_type - желаемый способ подтверждения (1 - SMS; 2 - USSD; 4 - только оплата WM-счета; 3 - WebMoney по какому-то ей одной известному алгоритму определит способ подтверждения, предпочтительный для данного юзера). sign, md5, secret_key - это поля для подтверждения аутентичности вашего запроса. Можно использовать ЛЮБОЙ из этих способов, тогда 2 других поля нужно оставить незаполненными. Мы в наших примерах будем использовать md5. Начнем писать нашу PHP-функцию, которая будет реализовывать работу с Х20: Code: if($step==1) { $md5=strtoupper(md5($wmid.$lmi_payee_purse.$lmi_payment_no.$lmi_clientnumber.$lmi_clientnumber_type.$secret_key)); $lmi_payment_desc=iconv("CP1251", "UTF-8", $lmi_payment_desc); $xml=" <merchant.request> <wmid>$wmid</wmid> <lmi_payee_purse>$lmi_payee_purse</lmi_payee_purse> <lmi_payment_no>$lmi_payment_no</lmi_payment_no> <lmi_payment_amount>$lmi_payment_amount</lmi_payment_amount> <lmi_payment_desc>$lmi_payment_desc</lmi_payment_desc> <lmi_clientnumber>$lmi_clientnumber</lmi_clientnumber> <lmi_clientnumber_type>$lmi_clientnumber_type</lmi_clientnumber_type> <lmi_sms_type>$lmi_sms_type</lmi_sms_type> <secret_key></secret_key> <sign></sign> <md5>$md5</md5> </merchant.request>"; $resxml=_GetAnswer($XML_addr[201], $xml); } В поле <md5> передается МД5-хеш строки параметров. Эта строка получается путем склейки параметров, среди которых $secret_key. В эту переменную мы будем передавать SecretKey из настроек нашего торгового кошелька в WM Merchant. Ответ сервера WebMoney: Code: <?xml version="1.0"?> <merchant.response> <operation wminvoiceid=""> <realsmstype></realsmstype> </operation> <retval>0</retval> <retdesc></retdesc> <userdesc></userdesc> </merchant.response> атрибут wminvoiceid - номер счета, выписанного юзеру, в системе WebMoney. Если возникла ошибка, то здесь будет пусто. realsmstype - какой способ подтверждения применен (1 - SMS; 2 - USSD; 4 - SMS и USSD не отправлялись, а только был выписан WM-счет). Возникает вопрос, а зачем нам это поле в ответе, ведь способ подтверждения мы сами назначили и передали в поле <lmi_sms_type> запроса. Дело в том, что если в <lmi_sms_type> было передано "3", то WebMoney самостоятельно приняла решение, какой способ подтверждения для юзера предпочтительный. Предположим, WebMoney решила, что предпочтительно отправить SMS, тогда в <realsmstype> мы увидим "1". retval - результат отработки запроса. "0" свидетельствует о том, что запрос успешно отработан, и WM-счет выписан (+ SMS\USSD отправлено). Другое значение retval свидетельствует об ошибке. retdesc - описание ошибки. userdesc - текст на русском языке, который можно транслировать юзеру. В нем WebMoney передает "юзеропонятный" текст ошибки, либо указания к дальнейшим действиям. Внимание! wminvoiceid нужно обязательно сохранить хотя бы в сессии, а лучше - в базе данных. Если юзер заказал подтверждение по SMS (realsmstype = 1), то на этом этапе у него нужно запросить код, который он получил в телефон. 2-й запрос Зачем нужен 2-й запрос? 1) Если юзер оплачивал WM-счет (realsmstype = 4) или подтверждал оплату по USSD (realsmstype = 2), иными словами, если оплата произошла без вашего участия, то 2-й запрос позволяет проверить состояние оплаты. Кстати, то же самое можно делать с помощью X18. 2) Если юзер подтверждал оплату по SMS (realsmstype = 1), после чего ввел полученный SMS-код на вашей стороне (на сайте или в программе), то 2-м запросом вы передаете этот SMS-код на сервер WebMoney и тем самым завершаете операцию оплаты. 3) Если юзер еще не успел оплатить (не подтвердил USSD и не оплатил WM-счет), то 2-й запрос позволяет отменить операцию. Отправляется на URL https://merchant.webmoney.ru/conf/xml/XMLTransConfirm.asp методом POST. Состав запроса: Code: <merchant.request> <wmid></wmid> <lmi_payee_purse></lmi_payee_purse> <lmi_clientnumber_code></lmi_clientnumber_code> <lmi_wminvoiceid></lmi_wminvoiceid> <secret_key></secret_key> <sign></sign> <md5></md5> </merchant.request> wmid и lmi_payee_purse - то же, что и в 1-м запросе. lmi_clientnumber_code - здесь нужно передать SMS-код, полученный от юзера, если оплата подтверждалась по SMS (realsmstype = 1). Если же оплата подтверждалась по USSD (realsmstype = 2) или был только выписан WM-счет (realsmstype = 4), то в этом поле нужно передать "0". lmi_wminvoiceid - номер счета, полученный в 1-м запросе (вы же его сохранили хотя бы в сессии?!). sign, md5, secret_key - это поля для подтверждения аутентичности вашего запроса. Можно использовать ЛЮБОЙ из этих способов, тогда 2 других поля нужно оставить незаполненными. Мы в наших примерах будем использовать md5. Наша функция дополнилась таким кодом: Code: if($step==1) { ... } elseif($step==2) { $md5=strtoupper(md5($wmid.$lmi_payee_purse.$lmi_wminvoiceid.$lmi_clientnumber_code.$secret_key)); $xml=" <merchant.request> <wmid>$wmid</wmid> <lmi_payee_purse>$lmi_payee_purse</lmi_payee_purse> <lmi_clientnumber_code>$lmi_clientnumber_code</lmi_clientnumber_code> <lmi_wminvoiceid>$lmi_wminvoiceid</lmi_wminvoiceid> <secret_key></secret_key> <sign></sign> <md5>$md5</md5> </merchant.request>"; $resxml=_GetAnswer($XML_addr[202], $xml); } Поле <md5> здесь формируется точно по такому же принципу, как и в 1-м запросе, только строка подписи формируется из других переменных. Ответ сервера WebMoney: Code: <merchant.response> <operation wmtransid="" wminvoiceid=""> <amount></amount> <operdate></operdate> <purpose></purpose> <pursefrom></pursefrom> <wmidfrom></wmidfrom> </operation> <retval>0</retval> <retdesc></retdesc> <userdesc></userdesc> </merchant.response> атрибут wmtransid - уникальный номер транзакции в системе WebMoney (если операция оплаты прошла успешно). operdate - дата и время проведения этой транзакции на сервере WebMoney (если операция оплаты прошла успешно). pursefrom и wmidfrom - кошелек и WMID плательщика (если операция оплаты прошла успешно). retval - результат отработки запроса. "0" свидетельствует о том, что запрос успешно отработан, и оплата успешно произведена. retdesc и userdesc - смысл у этих полей такой же, как и в 1-м запросе. Это, в принципе, уже финал. Осталось лишь обратить ваше внимание на несколько принципиальных моментов по поводу 2-го запроса: 1) Во-первых, получение retval = 0 и wmtransid > 0 - говорит о том, что оплата успешно состоялась! 2) Во-вторых, получение retval = 556 означает, что оплата еще не подтверждена (если был USSD или чистый WM-счет), либо SMS-код передан неверный (если было SMS-потверждение). 3) В-третьих, если вы хотите отменить операцию, то в lmi_clientnumber_code передавайте "-1". Если юзер еще не успел оплатить, то операция будет отменена и в ответе вы увидите retval = 557 или retval = 551. Рекоммендуем дать юзеру кнопку "отметить", чтобы он сам на вашей стороне мог инициировать отмену ранее заказанного платежа. 4) В-четвертых, если юзер оплачивал WM-счет или подтверждал оплату по USSD, то вы отправляете lmi_clientnumber_code = 0 и этим 2-м запросом просто проверяете текущее состояние оплаты. Можно его вообще не посылать, а вместо этого воспользоваться интерфейсом Х18. Однако, в любом случае помните, что при использовании Х20 сервер WebMoney не дергает ваш Result URL из настроек WM Merchant! Result URL задействуется только в случае "классической" оплаты через WM Merchant. Функция _WMXML20() Функция _WMXML20() для работы с Х20 включена в библиотеку XOWM. Ничего сверхъестественного она не делает. В зависимости от принятого параметра $step (1 или 2) отправляет соответственно 1-й или 2-й запрос. Набор входных параметров у этой функции одинаковый для обеих step (запросов). Он огромен: Code: function _WMXML20 ($step, $wmid, $lmi_payee_purse, $lmi_payment_no, $lmi_payment_amount, $lmi_payment_desc, $lmi_clientnumber, $lmi_clientnumber_type, $lmi_sms_type, $lmi_clientnumber_code, $lmi_wminvoiceid, $secret_key) { ... return $result; } Однако, поскольку у 1-го и 2-го запроса есть как общие параметры, так и отличающиеся, то некоторые параметры будут отсутствовать в вызове функции при 1-м запросе, а некоторые параметры будут отсутствовать в вызове функции при 2-м запросе. Вот пример вызова функции для 1-го запроса. Пустуют $lmi_clientnumber_code и $lmi_wminvoiceid: $res=_WMXML20($step, $wmid, $lmi_payee_purse, $lmi_payment_no, $lmi_payment_amount, $lmi_payment_desc, $lmi_clientnumber, $lmi_clientnumber_type, $lmi_sms_type, "", "", $secretkey); А вот пример вызова для 2-го запроса. Пустуют $lmi_payment_no, $lmi_payment_amount, $lmi_payment_desc, $lmi_clientnumber, $lmi_clientnumber_type, $lmi_sms_type: $res=_WMXML20($step, $wmid, $lmi_payee_purse, "", "", "", "", "", "", $lmi_clientnumber_code, $lmi_wminvoiceid, $secretkey); Понятное дело, функция и возвращает в 1-м и 2-м запросе несколько разный набор параметров в массиве $result. Если вы будете использовать библиотеку XOWM и не хотите читать предыдущие статьи нашего цикла о XML-интерфейсах, то сразу даём подсказку: для Х20 нужно в блоке настроек прописать $Global_WMID и $Path_Certs. Для работы библиотеки нужны расширения PHP: simplexml, iconv, curl. Логика со стороны клиента Здесь мы продемонстрировали работу Х20 в реализации на PHP. Не очень оригинально, тем не менее, понять логику вполне можно. А логика такая. 1) Демонстрируем юзеру, сколько и за что он сейчас будет платить. V 2) Юзер выбирает, как он хочет идентифицироваться в системе WebMoney (email, телефон, WMID) и как он хочет подтвердить оплату (SMS, USSD, либо только оплата WM-счета). V 3) По нажатию на кнопку посылаем 1-й запрос. V 4) Если есть ошибки (retval не 0) - отображаем на экране userdesc и просим повторить. Если же ошибок нет (retval = 0), то предлагаем юзеру ввести SMS-код (но только если было заказано подтверждение по SMS: realsmstype = 1) и подтвердить оплату. V 5) По нажатию на кнопку посылаем 2-й запрос. V 6) Если есть ошибки (любой retval кроме 0, 557, 551) - отображаем на экране userdesc и просим повторить. Если retval = 557 или retval = 551, то понимаем, что оплата была отменена (например, юзер в Кипере отказался от оплаты WM-счета). Если же retval = 0 и wmtransid > 0, то оплата подтверждена. Отображаем сообщение об УСПЕХЕ и отрабатываем бизнес-поведение при успешном платеже. Вот и всё. Еще на шаге 4 даем юзеру возможность отменить операцию. Тогда посылаем 2-й запрос с lmi_clientnumber_code = -1 , а в ответе получим retval = 557 или retval = 551. © Никита Сенченко, 06.07.2011 http://owebmoney.ru/articles/x20/