YooMoney API
Old versions of the API
Help
Sign up for YooMoney
Processing HTTP notifications
Before the user sees the payment confirmation page, YooMoney sends an Order verification (checkOrder) request to the address specified in the technical questionnaire.
The request arrives in either open or encrypted format, depending on the security measures the store is using.
You must process the request, then form a response and send it.
Below is an example of a function that processes the request and sends a response, depending on the security scheme and the current action (checkOrder/paymentAviso):
PHP
/**
 * Handles "checkOrder" and "paymentAviso" requests.
 * @param array $request payment parameters
 */
public function processRequest($request) {
    $this->log("Start " . $this->action);
    $this->log("Security type " . $this->settings->SECURITY_TYPE);
    if ($this->settings->SECURITY_TYPE == "MD5") {
        $this->log("Request: " . print_r($request, true));
        // If the MD5 checking fails, respond with "1" error code
        if (!$this->checkMD5($request)) {
            $response = $this->buildResponse($this->action, $request['invoiceId'], 1);
            $this->sendResponse($response);
        }
    } else if ($this->settings->SECURITY_TYPE == "PKCS7") {
        // Checking for a certificate sign. If the checking fails, respond with "200" error code.
        if (($request = $this->verifySign()) == null) {
            $response = $this->buildResponse($this->action, null, 200);
            $this->sendResponse($response);
        }
        $this->log("Request: " . print_r($request, true));
    }
    $response = null;
    if ($this->action == 'checkOrder') {
        $response = $this->checkOrder($request);
    } else {
        $response = $this->paymentAviso($request);
    }
    $this->sendResponse($response);
}
 
Checking the control amount
PHP
/**
 * Checking the MD5 sign.
 * @param array $request payment parameters
 * @return bool true if MD5 hash is correct
 */
private function checkMD5($request) {
    $str = $request['action'] . ";" .
        $request['orderSumAmount'] . ";" . $request['orderSumCurrencyPaycash'] . ";" .
        $request['orderSumBankPaycash'] . ";" . $request['shopId'] . ";" .
        $request['invoiceId'] . ";" . $request['customerNumber'] . ";" . $this->settings->SHOP_PASSWORD;
    $this->log("String to md5: " . $str);
    $md5 = strtoupper(md5($str));
    if ($md5 != strtoupper($request['md5'])) {
        $this->log("Wait for md5:" . $md5 . ", recieved md5: " . $request['md5']);
        return false;
    }
    return true;
}
Checking the signature
PHP
/**
 * Checking for sign when XML/PKCS#7 scheme is used.
 * @return array if request is successful, returns key-value array of request params, null otherwise.
 */
private function verifySign() {
    $descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
    $certificate = 'yookassa.pem';
    $process = proc_open('openssl smime -verify -inform PEM -nointern -certfile ' . $certificate . ' -CAfile ' . $certificate,
        $descriptorspec, $pipes);
    if (is_resource($process)) {
        // Getting data from request body.
        $data = file_get_contents($this->settings->request_source); // "php://input"
        fwrite($pipes[0], $data);
        fclose($pipes[0]);
        $content = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $resCode = proc_close($process);
        if ($resCode != 0) {
            return null;
        } else {
            $this->log("Row xml: " . $content);
            $xml = simplexml_load_string($content);
            $array = json_decode(json_encode($xml), TRUE);
            return $array["@attributes"];
        }
    }
    return null;
}
If the security checks were passed successfully, you can perform business processing of the request.
checkOrder
PHP
/**
 * CheckOrder request processing. We suppose there are no item with price less
 * than 100 rubles in the shop.
 * @param array $request payment parameters
 * @return string prepared XML response
 */
private function checkOrder($request) {
    $response = null;
    if ($request['orderSumAmount'] < 100) {
        $response = $this->buildResponse($this->action, $request['invoiceId'], 100, "The amount should be more than 100 rubles.");
    } else {
        $response = $this->buildResponse($this->action, $request['invoiceId'], 0);
    }
    return $response;
}
paymentAviso
PHP
/**
 * PaymentAviso request processing.
 * @param array $request payment parameters
 * @return string prepared response in XML format
 */
private function paymentAviso($request) {
    return $this->buildResponse($this->action, $request['invoiceId'], 0);
}
Forming the response
PHP
/**
 * Building XML response.
 * @param string $functionName "checkOrder" or "paymentAviso" string
 * @param string $invoiceId transaction number
 * @param string $result_code result code
 * @param string $message error message. May be null.
 * @return string prepared XML response
 */
private function buildResponse($functionName, $invoiceId, $result_code, $message = null) {
    try {
        $performedDatetime = Utils::formatDate(new DateTime());
        $response = '<?xml version="1.0" encoding="UTF-8"?><' . $functionName . 'Response performedDatetime="' . $performedDatetime .
            '" code="' . $result_code . '" ' . ($message != null ? 'message="' . $message . '"' : "") . ' invoiceId="' . $invoiceId . '" shopId="' . $this->settings->SHOP_ID . '"/>';
        return $response;
    } catch (\Exception $e) {
        $this->log($e);
    }
    return null;
}
See also
HTTP notifications about payments