- PVSM.RU - https://www.pvsm.ru -
TL;DR. Я собрал платный API для ИИ‑агентов на протоколе x402: агент получает HTTP 402, платит в USDC и получает подписанный сертификат проверки своего кода. Довёл до продакшена, прогнал сквозной путь, задеплоил. Потом проверил доступные данные о рынке и понял, что покупателей в том объёме, на который я рассчитывал, пока не видно. По дороге поймал четыре бага, каждый из которых выглядел как правильно работающий код. Ниже — что построил, что сломалось, что показали цифры и какое одно правило ловило всё.
x402 — протокол, который возвращает к жизни забытый код ответа HTTP 402 Payment Required. Сервер отвечает 402 с условиями оплаты, клиент подписывает платёж в стейблкоине и повторяет запрос. Без аккаунтов, без API‑ключей, без подписок. С апреля 2026 года протокол развивается под Linux Foundation. [1]
Смысл был такой. ИИ‑агенты пишут код, и этот код часто содержит уязвимости. По данным Veracode [2], ИИ‑код вносит уязвимости из OWASP Top 10 в 45% случаев. По данным CodeRabbit [3], security‑находок в нём в 1,57 раза больше, чем в человеческом, а по XSS отдельно — в 2,74 раза. Если агент перед релизом будет сам платить пару центов за независимую проверку и получать подписанный протокол — это M2M‑рынок, где покупатель не человек, а программа.
FastAPI‑шлюз. Эндпоинт /v1/audit/{suite_id} без оплаты отвечает 402 с x402-payload: сеть, актив, сумма, адрес получателя.
Facilitator — отдельный компонент, который проверяет и проводит платёж. Шлюз сам не держит ключей плательщика.
Изолированный прогон. После оплаты артефакт проверяется в одноразовом контейнере: docker run --rm, без сети, read‑only, non‑root, с лимитами CPU и памяти.
Тест‑сьют xss-cwe80-v1 — детерминированные сигнатурные правила на XSS: innerHTML, dangerouslySetInnerHTML, v-html, |safe, eval и так далее.
Attestation — результат, подписанный ed25519: хэш артефакта, идентификатор сьюта, сколько проверок прошло, сколько провалилось, распределение по severity, время.
Rate limit в Redis: больше 100 отказов в минуту с одного адреса — 429. Запросы с проверенной оплатой под этот лимит не попадают.
PostgreSQL для журнала транзакций, деплой на Railway.
Так выглядит ответ на запрос без оплаты:
{
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "base-sepolia",
"asset": "USDC",
"payTo": "0x0000000000000000000000000000000000000000",
"maxAmountRequired": "100000",
"resource": "/v1/audit/xss-cwe80-v1",
"description": "AI-Auditor attestation run: xss-cwe80-v1",
"mimeType": "application/json",
"maxTimeoutSeconds": 120
}]
}
О самом продукте важно сказать одно: сертификат не утверждает «уязвимостей нет». Конечный набор проверок физически не может доказать отсутствие дефекта. Он фиксирует только то, что можно подтвердить.
Чем проверено — test_suite_id с версией сьюта. Что именно проверено —artifact_hash: изменил одну строку, и сертификат к этому коду уже не относится. Когда — timestamp. С каким итогом — N проверок, M провалов и распределение по severity, а не «безопасно». Кто за это отвечает — подпись issuer_signature.
Это не заменяет пентест и не гарантия безопасности — это протокол ограниченного набора проверок.
Facilitator хранит использованные nonce, чтобы один платёж нельзя было предъявить дважды. Код выглядел корректно:
async def handle_audit(suite_id: str, request: Request):
settings = get_settings()
facilitator = build_facilitator(settings) # новый объект на каждый запрос
...
Проблема в одной строке. Facilitator создавался заново на каждый HTTP‑запрос — вместе с пустым множеством использованных nonce. Проверка «этот nonce уже был» не могла сработать ни разу: к моменту второго запроса память первого уже не существовала. Ветка nonce_already_used была мёртвым кодом.
От двойного учёта спасал только UNIQUE(tx_hash) в базе. Но tx_hash в тестовом режиме вычислялся из кошелька, суммы и nonce — достаточно поменять сумму, и повтор проходил.
Фикс — перенести создание в lifespan, один экземпляр на процесс:
@asynccontextmanager
async def lifespan(app: FastAPI):
await database.connect()
app.state.facilitator = build_facilitator(get_settings())
yield
await database.disconnect()
Проверка после фикса: два вызова с одним nonce и разными суммами — первый 200 с сертификатом, второй 402 nonce_already_used.
Инсайт: время жизни объекта — часть контракта, а не деталь реализации.
Первый деплой на Railway отдавал 502: приложение слушало не тот порт, на который платформа отправляла трафик. В Dockerfile порт был захардкожен:
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Исправил на чтение переменной окружения:
CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-8000}"]
Заработало. На следующем автодеплое снова 502. В логах приложения — ни одной ошибки: Uvicorn running on http://0.0.0.0:8080.
Причина: у домена target port зафиксирован на 8000, а платформа при новом деплое выдала контейнеру другой $PORT. Приложение слушает, но не там, куда идёт трафик. В первый раз сработало по совпадению.
Фикс — явная переменная PORT=8000 на сервисе, чтобы значение не зависело от того, что платформа выдаст в этот раз.
Инсайт: «заработало» после фикса ещё не значит «починилось». Иногда это значит «совпало».
После деплоя всё выглядело нормально: /healthz отвечал 200, платформа показывала зелёный статус. Первый же запрос, который писал в базу, упал с 500:
asyncpg.exceptions.UndefinedTableError: relation "agent_transactions" does not exist
Health check базу не трогал, поэтому и не мог заметить, что в ней ничего нет.
Схему никто никогда не применял руками. Локально это делал Docker: официальный образ Postgres выполняет скрипты из docker-entrypoint-initdb.d при первом старте контейнера с пустым volume. Шаг происходил молча, и поэтому его не было ни в одной инструкции деплоя. На managed‑базе этот механизм не срабатывает — схему пришлось накатить вручную и дописать этот шаг в runbook.
Инсайт: «работает у меня» часто означает «работает благодаря шагу, который никто не делал сознательно». И health check, который не проверяет зависимости, сообщает о здоровье сервиса, а не системы.
Чтобы разрабатывать и тестировать платёжный путь без реального блокчейна и реальных денег, в проекте есть тестовый facilitator. Он принимает строку вида wallet:...;amount:...;nonce:..., проверяет формат и сумму — и считает платёж проведённым.
Сквозной тест с ним проходил идеально: 402, оплата, прогон, подписанный сертификат. Слишком идеально — заглушка принимает любую строку правильного формата. Подставил сумму и новый nonce — получил сертификат, не заплатив ничего.
А потом я посмотрел на переменные продакшен‑окружения. Там стояло FACILITATOR_MODE=mock.
Закрыл флагом PUBLIC_MODE: при нём платный роутер вообще не регистрируется в приложении. Проверил не значение флага, а поведение: при true путь /v1/audit/* отсутствует в /openapi.json, при false — присутствует.
Инсайт: тестовый режим сам по себе не дыра. Дыра — когда ничто не мешает ему доехать до продакшена.
Пока я отлаживал, стоило проверить главное допущение — что агенты действительно платят. Сразу оговорюсь: собственный рынок я не измерял. Ссылку на сервис я никому не показывал, поэтому основное ниже — внешние данные, а не результаты моего продукта.
Доля реально агентского трафика. TRM Labs [4] разобрала около $52,7 млн x402-платежей — почти 199 млн расчётов в Base, Solana и Polygon с мая 2025 года. После фильтрации активности, не похожей на настоящую коммерцию, агентской выглядит лишь 0,6–7,5% объёма. Остальное — скрипты, плановые процессы и транзакции самому себе, которые в блокчейне неотличимы от платежей ИИ‑агентов. Сами исследователи оговариваются, что методика может занижать долю: агент, который раз за разом покупает один и тот же сервис, по их критериям выглядит как скрипт. Но главный вывод это не отменяет: рост транзакций x402 — не прокси роста автономной коммерции (пересказ на PYMNTS [5]).
Каталог, в который сложно попасть. Один из основных путей, которым агенты находят x402-сервисы, — авто‑индексация Bazaar [6]: после проведённого платежа facilitator сам добавляет сервис в каталог. Судя по сообщениям разработчиков, это работает нестабильно: платёж проходит, а сервис в каталоге не появляется. В одних случаях facilitator вообще не возвращает служебный заголовок EXTENSION-RESPONSES (#2112 [7]), в других возвращает статус «в обработке», но индексации так и не происходит (#2691 [8]). Похожие жалобы есть и в августе (#3045 [9]), и у другого facilitator'а — PayAI (#53 [10]). Сам я до этого шага не дошёл, так что это чужой опыт, а не мой.
Экономика — не барьер. CDP Facilitator [11]: первые 1000 расчётов в месяц бесплатно, дальше $0,001 за транзакцию. Инфраструктура почти ничего не стоит.
Мои собственные метрики. Внешнего трафика не было вовсе. В журнале шесть записей — три открытия лендинга и три обращения к двум эндпоинтам‑заглушкам, которые проверяют интерес к будущим функциям, — и все сделаны в день тестирования моими проверочными запросами. Это не данные о спросе, это отсутствие измерения. Ещё одна находка: request_ip за прокси платформы — это адрес прокси, а не клиента, поэтому считать уникальных посетителей по нему нельзя. Отличать свои запросы от чужих пришлось по времени, поэтому после теста я начал записывать User‑Agent — чтобы в следующий раз не гадать.
Итог: инфраструктура x402 готова, работает и дешёвая. Массового потока платящих агентов, которых можно было бы поймать публикацией API, по этим данным пока не видно.
Код в этом проекте писал ИИ‑агент — Claude Code. Я ставил задачи, проверял результат и принимал решения. И почти все находки сводятся к одной формуле:
Декларация — не подтверждённый факт.
Все четыре бага — один класс ошибки: что‑то сообщало о себе не то, чем являлось.
Ветка nonce_already_used в коде — не то же самое, что работающая защита от повтора.
«Заработало после фикса» — не то же самое, что «починилось».
Зелёный health check — не то же самое, что рабочая система.
Успешный сквозной тест — не то же самое, что проверенная оплата.
Тот же класс встречался и за пределами багов. Автоматически сгенерированная OpenAPI‑спецификация обещала 200, реальный вызов вернул 404. Отчёт агента «исправил» — не то же самое, что дифф.
Практика, которая это ловит, скучная и простая:
Требовать сырой вывод, а не пересказ. Не «покажи, что всё хорошо», а «покажи вывод команды». Это работает в обе стороны: однажды строку контекста в диффе приняли за дублирование кода, и только полный файл показал, что всё в порядке.
Проверять поведение, а не конфигурацию. Не «переменная выставлена», а «эндпоинт отсутствует в спеке при этом значении».
Постоянный контекст для агента — файл CLAUDE.md [12] в корне репозитория: принципы, команды, текущие решения. Новая сессия начинается не с нуля.
Журнал решений — decisions.md [13], только дописывается, не редактируется. Каждое решение: вопрос, варианты, выбор, обоснование. Плюс стоп‑лист отклонённых путей, чтобы агент не предлагал их заново.
Отдельно про секреты. За проект пароль от продовой базы один раз попал в вывод команды — CLI платформы показал его открытым текстом там, где я ожидал маску. Ротировал сразу. Приватный ключ подписи генерировался только в файл, минуя вывод в терминал, — агент сам отказался печатать его в чат, сославшись на решение, записанное в репозитории ранее. Журнал решений — решает.
Продукт не нашёл рынка — в том виде и в тот момент, на которые я рассчитывал. Но цикл занял дни, а не месяцы, и закончился данными.
Если бы начинал заново — сначала проверил бы покупателя, потом строил бы инфраструктуру. Звучит очевидно, но когда строить интереснее, чем проверять, очевидное легко пропустить.
Если у вас есть данные по реальному агентскому трафику — x402 или любому другому протоколу оплаты для агентов, — интересно сверить. Особенно если ваши цифры расходятся с моими.
Автор: Laratok
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/postgresql/458689
Ссылки в тексте:
[1] Linux Foundation.: https://docs.cdp.coinbase.com/x402/support/x402-foundation
[2] Veracode: https://www.veracode.com/resources/analyst-reports/2025-genai-code-security-report/
[3] CodeRabbit: https://www.coderabbit.ai/blog/state-of-ai-vs-human-code-generation-report
[4] TRM Labs: https://www.trmlabs.com/trm-tech-blog/whos-actually-paying-measuring-ai-agent-payments-onchain
[5] пересказ на PYMNTS: https://www.pymnts.com/news/artificial-intelligence/2026/agentic-payments-are-growing-most-x402-payments-are-not-from-ai-agents
[6] авто‑индексация Bazaar: https://docs.x402.org/extensions/bazaar
[7] #2112: https://github.com/x402-foundation/x402/issues/2112
[8] #2691: https://github.com/x402-foundation/x402/issues/2691
[9] #3045: https://github.com/x402-foundation/x402/issues/3045
[10] #53: https://github.com/PayAINetwork/x402-solana/issues/53
[11] CDP Facilitator: https://docs.cdp.coinbase.com/x402/core-concepts/facilitator
[12] CLAUDE.md: http://CLAUDE.md
[13] decisions.md: http://decisions.md
[14] Источник: https://habr.com/ru/articles/1086276/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1086276
Нажмите здесь для печати.