Интеграция API платежей USDT на Python

Создавайте ссылки на оплату USDT TRC-20 на Python, повторяйте запросы с постоянным ключом идемпотентности и проверяйте подписи платежей.

Интеграция работает на сервере

Пример использует Python 3.11+ и встроенные модули без SDK. Импорт не делает запрос API. Никогда не отправляйте API-ключ и ключ подписи в браузерную сборку.

Сначала настройте HTTPS-вебхук. Задайте DEDYX_API_KEY и DEDYX_WALLET в окружении сервера. Скачайте dedyx_client.py и импортируйте в серверном коде.

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

Создание платежа с безопасными повторами

Python 3.11+ · клиент для скачивания
"""Python 3.11+ server-side example; no calls or credentials at import time."""
import hashlib
import hmac
import json
import random
import re
import time
from urllib.error import HTTPError, URLError
from urllib.request import HTTPRedirectHandler, Request, build_opener

API = 'https://api.dedyx.com/api/v1'


class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None  # Never forward an API key to a redirected host.


def create_payment(api_key, wallet, amount, description, idempotency_key):
    """Persist the key and these fields with your order BEFORE calling this function."""
    if not re.fullmatch(r'[A-Za-z0-9._:-]{8,128}', idempotency_key):
        raise ValueError('Use a persisted 8–128 character idempotency key.')
    body = json.dumps({'merchant_wallet': wallet, 'amount': amount,
                       'description': description}, separators=(',', ':')).encode()
    request = Request(API + '/payments', data=body, method='POST', headers={
        'X-API-Key': api_key, 'Idempotency-Key': idempotency_key,
        'Content-Type': 'application/json'})
    opener = build_opener(NoRedirect())
    for attempt in range(3):
        delay = 0.5 * (2 ** attempt) + random.uniform(0, 0.25)
        try:
            with opener.open(request, timeout=10) as response:
                return json.load(response)
        except HTTPError as error:
            if error.code not in (429, 500, 502, 503, 504) or attempt == 2:
                raise
            retry_after = error.headers.get('Retry-After', '')
            if retry_after.isascii() and retry_after.isdigit():
                seconds = int(retry_after)
                if seconds > 60:
                    raise  # Schedule later with the SAME stored key/body.
                delay = max(delay, seconds)
            error.close()  # nginx may return HTML; do not assume an error JSON body.
        except (URLError, TimeoutError):
            if attempt == 2:
                raise  # Outcome may be uncertain; preserve the key and reconcile.
        time.sleep(delay)

Клиент использует таймаут 10 секунд и не более трёх попыток. Ответы 429 и выбранные 5xx повторяются с теми же сериализованным телом и ключом идемпотентности. Числовой Retry-After соблюдается; длительное ожидание передаётся планировщику задач. Ошибки nginx могут быть HTML, поэтому клиент проверяет статус без предположения о JSON.

409 не повторяется вслепую: проверьте настройки вебхука, занятый адрес и изменение тела при том же ключе. При исчерпанных или неопределённых повторах сохраняйте ключ и сверяйте состояние; стандартное хранение повторов — 24 часа. Ключ содержит 8–128 ASCII-букв, цифр или ._:-.

Связь ответа с заказом

Пример вызова — нужны ваше окружение и заказ
import os
from dedyx_client import create_payment

# These fields must come from a persisted order record.
payment = create_payment(
    api_key=os.environ["DEDYX_API_KEY"],
    wallet=os.environ["DEDYX_WALLET"],
    amount="49.00",
    description="Order #1024",
    idempotency_key="order-1024-v1",
)
# Persist payment["payment_id"] and the response before redirecting.
print(payment["payment_url"])

Сохраните ответ вместе с заказом до перенаправления клиента на payment_url. Для повторов этого заказа используйте тот же ключ и поля. Не помещайте персональные данные в description.

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

Python 3.11+ · проверка подписи и ID события
import hashlib
import hmac
import json
import re
import time

def verify_webhook(raw_body, timestamp, signature, header_event_id, key_id, keys, now=None):
    """keys maps saved X-Dedyx-Key-ID values to the full whsec_... string."""
    if not re.fullmatch(r'[0-9]{1,12}', timestamp or ''):
        raise ValueError('Invalid timestamp')
    if abs((time.time() if now is None else now) - int(timestamp)) > 300:
        raise ValueError('Stale signature')
    if key_id not in keys or not re.fullmatch(r'v1=[0-9a-f]{64}', signature or ''):
        raise ValueError('Unknown signing key or signature format')
    expected = 'v1=' + hmac.new(keys[key_id].encode(), timestamp.encode() + b'.' + raw_body,
                               hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, signature):
        raise ValueError('Invalid signature')
    event = json.loads(raw_body)
    if not isinstance(event, dict) or not isinstance(event.get('event_id'), str) or not event['event_id'] or event['event_id'] != header_event_id:
        raise ValueError('Event ID mismatch')
    # A valid signature is only the first check; validate your own order before fulfilment.
    return event

Передайте исходные байты запроса / Buffer, X-Dedyx-Timestamp, X-Dedyx-Signature, X-Dedyx-Event-ID и X-Dedyx-Key-ID. Словарь ключей содержит сохранённые ID и полные секреты whsec_... . Не запускайте JSON middleware до сохранения исходных байтов.

После проверки требуйте PAID, сопоставьте событие с сохранённым заказом и точно сравните сумму. Атомарно сохраняйте event_id и выполнение заказа. Повтор возвращает 2xx без повторного действия. См. доставку и исключение повторов; одна проверка подписи никогда не должна выдавать товар.

Перед включением клиентских платежей

  • Проверьте верную подпись, изменённое тело, устаревшее время и неизвестный ключ.
  • Проверьте повторное событие и сбой приёмника во время выполнения заказа.
  • Проверьте таймаут API после успешного создания: повторите исходный ключ.
  • Проверьте 429 с Retry-After, HTML-ошибки nginx и временный 503.
  • Разберите истечение, отменённые заказы и поздние переводы с поддержкой.

Полный чеклист запуска и пример атомарного выполнения · Ошибки API · Запросить доступ к бете