Ошибка 204 Tinkoff: неверный токен - причины и исправление

    Разработчики, интегрирующие платёжный сервис Тинькофф, нередко сталкиваются с ошибкой ErrorCode: '204' и сообщением «Неверный токен. Проверьте пару TerminalKey/SecretKey». Это означает, что запрос к API сформирован некорректно - скорее всего, неправильно вычислен токен (подпись). В этой статье мы разберём, как правильно генерировать токен для запроса проверки статуса платежа, и исправим типичную ошибку в коде на Python с библиотекой aiohttp.

    Почему возникает ошибка 204

    Код 204 в ответе Tinkoff API указывает на то, что переданный параметр Token не совпадает с тем, который ожидает сервер. Токен - это SHA-256 хеш от конкатенации значений всех параметров запроса, отсортированных в алфавитном порядке, с добавлением секретного ключа (SecretKey). Ошибка чаще всего возникает, если:

    • Неправильно собран набор полей для хеширования;
    • Не учитываются все обязательные параметры запроса;
    • Используется неверный SecretKey или TerminalKey;
    • Порядок конкатенации не соответствует алфавитному.

    Как правильно генерировать токен по документации

    Согласно официальной документации Тинькофф, для формирования токена необходимо:

    1. Выбрать все параметры JSON-запроса, исключая сам Token;
    2. Отсортировать их ключи в алфавитном порядке;
    3. Склеить значения этих параметров (без ключей) в строку;
    4. Добавить в конец строки SecretKey;
    5. Вычислить SHA-256 хеш от полученной строки (в нижнем регистре).

    Важно: все значения должны быть строками. Если значение имеет тип int или float, его нужно привести к строке.

    Исправляем код проверки статуса платежа

    В исходном примере токен формировался как passwordd + str(order_id) + Ter_key. Это неверно по нескольким причинам:

    • Параметр TerminalKey не включён в хеш, хотя он обязателен;
    • Отсутствует сортировка ключей;
    • Вместо SecretKey используется passwordd (возможно, опечатка).

    Исправленный вариант функции на Python с использованием библиотеки hashlib:

    import hashlib
    import json
    
    def generate_token(params: dict, secret_key: str) -> str:
        # Убираем Token из словаря
        params.pop('Token', None)
        # Сортируем ключи по алфавиту
        sorted_keys = sorted(params.keys())
        # Склеиваем значения
        concatenated = ''.join(str(params[k]) for k in sorted_keys)
        # Добавляем SecretKey
        data = concatenated + secret_key
        # SHA-256 хеш
        return hashlib.sha256(data.encode('utf-8')).hexdigest()
    
    async def check_payment_status(order_id: int):
        params = {
            "TerminalKey": Ter_key,
            "PaymentId": order_id
        }
        params['Token'] = generate_token(params, secret_key)
        async with aiohttp.ClientSession() as session:
            async with session.post(TINKOFF_API_URL_get, json=params) as response:
                data = await response.json()
                if data.get("Success"):
                    return data.get("Status")
                else:
                    return None

    Обратите внимание: secret_key - это строка из личного кабинета Тинькофф, не путайте с TerminalKey. В приведённом примере мы корректно сортируем ключи (PaymentId, TerminalKey) и добавляем секретный ключ в конец.

    Дополнительные рекомендации

    Если ошибка 204 продолжает появляться:

    • Проверьте, что TerminalKey и SecretKey соответствуют друг другу (например, не перепутаны кавычки или лишние пробелы);
    • Убедитесь, что PaymentId передан как строка, а не число - в некоторых версиях API это имеет значение;
    • Протестируйте запрос через Postman или curl, чтобы изолировать проблему от кода.

    Часто задаваемые вопросы