Перейти к основному содержимому

Вебхуки

Для работы с вебхуками должно быть выдано разрешение ManageWebhookData.

Вебхук — это POST-запрос, который Точка отправляет на указанный вами URL, когда происходит важное событие по вашим счетам: например, поступил или ушёл платёж. Так вам не нужно постоянно опрашивать API — банк сам уведомляет ваш сервис.

В теле вебхука приходит JWT-токен в виде строки, подписанный по алгоритму RS256. Его нужно расшифровать на своей стороне.

Проверка подлинности вебхука​

Обязательно проверяйте подпись

Прежде чем доверять данным из вебхука, проверьте его подпись публичным ключом Точки. Если подпись не сходится — это значит, что запрос пришёл не от Точка Банка, и обрабатывать его нельзя.

Инфо

Вебхуки отправляются только об успешных операциях. Если вебхук не пришёл, получите информацию о платеже:

  • методом Get Payment Operation Info, если оплата проходила по платёжной ссылке.
  • методом Get Qr Codes Payment Status, если оплата проходила по QR-коду.
  • методомGet Statement, если оплата проходила по реквизитам. Не забудьте создать выписку методом Init Statement.

Виды событий​

Сейчас доступно пять видов событий. По каждому — отдельная страница с описанием, кому оно подходит, какие поля приходят и примером тела:

Несколько особенностей в работе вебхуков​

  • Если на отправленный вебхук мы не получили ответ с кодом HTTP 200, а получили любой другой, то будем повторять отправку 30 раз с интервалом 10 секунд.
  • При создании или изменении вебхука мы проверяем доступность вашего хоста — отправляем по одному тестовому вебхуку на каждое событие, на которое вы подписаны. Если в ответ не придёт код HTTP 200, вебхук не будет создан или изменён.
  • Подключить или изменить вебхук можно только по протоколу HTTPS на порт 443. Другой порт или протокол использовать нельзя.
  • Вебхук отправляется с заголовком Content-Type: text/plain — в теле приходит «голая» строка JWT, а не JSON.

Примеры обработки вебхуков​

Примеры кода, который принимает вебхук и проверяет его подпись.

Важно

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

Python
from aiohttp import web
import jwt
from jwt import exceptions
import json

// Публичный ключ Точка Банка. Может быть получен из https://enter.tochka.com/doc/openapi/static/keys/public
key_json = '{"kty":"RSA","e":"AQAB","n":"rwm77av7GIttq-JF1itEgLCGEZW_zz16RlUQVYlLbJtyRSu61fCec_rroP6PxjXU2uLzUOaGaLgAPeUZAJrGuVp9nryKgbZceHckdHDYgJd9TsdJ1MYUsXaOb9joN9vmsCscBx1lwSlFQyNQsHUsrjuDk-opf6RCuazRQ9gkoDCX70HV8WBMFoVm-YWQKJHZEaIQxg_DU4gMFyKRkDGKsYKA0POL-UgWA1qkg6nHY5BOMKaqxbc5ky87muWB5nNk4mfmsckyFv9j1gBiXLKekA_y4UwG2o1pbOLpJS3bP_c95rm4M9ZBmGXqfOQhbjz8z-s9C11i-jmOQ2ByohS-ST3E5sqBzIsxxrxyQDTw--bZNhzpbciyYW4GfkkqyeYoOPd_84jPTBDKQXssvj8ZOj2XboS77tvEO1n1WlwUzh8HPCJod5_fEgSXuozpJtOggXBv0C2ps7yXlDZf-7Jar0UYc_NJEHJF-xShlqd6Q3sVL02PhSCM-ibn9DN9BKmD"}'
key = json.loads(key_json)
jwk_key = jwt.jwk_from_dict(key)


async def handle(request: web.Request):
payload = await request.text()

try:
# тело вебхука
webhook_jwt = jwt.JWT().decode(
message=payload,
key=jwk_key,
)
except exceptions.JWTDecodeError:
# Неверная подпись, вебхук не от Точка Банка или с ним что-то не так
pass

return web.Response(status=200)


app = web.Application()
app.router.add_route('POST', '/', handle)

if __name__ == '__main__':
web.run_app(app, port=80)

PHP
<?php
require __DIR__ . "/vendor/autoload.php";
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;


$entityBody = file_get_contents("php://input");

// Публичный ключ Точка Банка. Может быть получен из https://enter.tochka.com/doc/openapi/static/keys/public
$json_key = '{"kty":"RSA","e":"AQAB","n":"rwm77av7GIttq-JF1itEgLCGEZW_zz16RlUQVYlLbJtyRSu61fCec_rroP6PxjXU2uLzUOaGaLgAPeUZAJrGuVp9nryKgbZceHckdHDYgJd9TsdJ1MYUsXaOb9joN9vmsCscBx1lwSlFQyNQsHUsrjuDk-opf6RCuazRQ9gkoDCX70HV8WBMFoVm-YWQKJHZEaIQxg_DU4gMFyKRkDGKsYKA0POL-UgWA1qkg6nHY5BOMKaqxbc5ky87muWB5nNk4mfmsckyFv9j1gBiXLKekA_y4UwG2o1pbOLpJS3bP_c95rm4M9ZBmGXqfOQhbjz8z-s9C11i-jmOQ2ByohS-ST3E5sqBzIsxxrxyQDTw--bZNhzpbciyYW4GfkkqyeYoOPd_84jPTBDKQXssvj8ZOj2XboS77tvEO1n1WlwUzh8HPCJod5_fEgSXuozpJtOggXBv0C2ps7yXlDZf-7Jar0UYc_NJEHJF-xShlqd6Q3sVL02PhSCM-ibn9DN9BKmD"}';
$jwks = json_decode($json_key, true, 512, JSON_THROW_ON_ERROR);

try {
$decoded = JWT::decode($entityBody, JWK::parseKey($jwks,"RS256"));
} catch (\UnexpectedValueException $e) {
// Неверная подпись, вебхук не от Точка Банка или с ним что-то не так
echo "Invalid webhook";
}


// Тело вебхука
$decoded_array = (array) $decoded;


http_response_code(200);
Java
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jwt.SignedJWT;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;

@RestController
@RequestMapping("/")
public class WebhookResource {

@PostMapping(value = "/")
public void tochkaWebhook(@RequestBody String webhookData) throws ParseException, JOSEException {

// Публичный ключ Точка Банка. Может быть получен из https://enter.tochka.com/doc/openapi/static/keys/public
var jsonKey = "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"raJQJyBXIgS1YzYFkmQGq5XtadLVvMcx5u-guR2r5ZgSb-HGUG7HF5NM-NJeL9YrVtjjGf8VNLpwGbeejsS9LRniPfKkCYaVqV1DSGOZ6RTOtqN3jKW1W86cVb-LffrQo3eFhPX5V464uduPu9RouFplQ7wprY5ewke0Yj0FCOr6Ebxlpql-aJp_wk8JSzzFN17IC5tfUXgGDjEmnMjxag_CntnJtKWmw69ivhrq5sTPspclL3Ij8K_Qk0MwAZFCci25WxIuKQe7Mk4dvay6CUfrCbAgEtqMcWUSqoG7pdBig59lo-kIMWvVQIAWjo2JhI7VlI_ssvFtiJg5T9myE914aESFZ8jEheQv-4kZ81F0qk02k2mJ4C7AasGhbzC4F8YQ7nbr49v1n_j8udNZZXA8vI2hacG517A66-uvEHIxXRUo_gIcubR-vdbJbaK_k8JRLJNmdf4B9HchJ6VD9aGjMT0GYfhQ8jf16E1L_U4G4XLB5cnb0h88PD2MaMGP\"}";
var jwkKey = JWK.parse(jsonKey);

var jwtData = SignedJWT.parse(webhookData);

var verifier = new RSASSAVerifier(jwkKey.toRSAKey().toRSAPublicKey());
if (!jwtData.verify(verifier)) {

// Неверная подпись, вебхук не от Точка Банка или с ним что-то не так
System.out.println("Invalid webhook");
return;
}

// Тело вебхука
var webhookParsedData = jwtData.getJWTClaimsSet().getClaims();
return;
}
}

Вебхуками можно управлять с помощью методов​

  • Get Webhooks — получить список всех вебхуков, настроенных на приложение.
  • Create Webhook — создать новый вебхук.
  • Edit Webhook — изменить URL или тип существующего вебхука.
  • Delete Webhook — удалить вебхук.
  • Send Webhook — отправить тестовый вебхук.