Интеграция 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+ 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.
Проверка исходного тела вебхука
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 · Запросить доступ к бете