Начало
Быстрый старт
Поднять стенд, получить ключ и увидеть первый ответ мока — от нуля до ответа за пять минут.
На этой странице · 7
Ниже — путь от пустой машины до первого ответа мока и до записи об этом вызове в журнале. Все команды и весь вывод в этом разделе сняты с работающего стенда, а не составлены по памяти.
Шаг 1. Поднимите стенд
docker compose up
Compose поднимает базу, шлюз и кабинет: API на порту 8080, веб на 3100.
Миграции накатываются сами; на пустой базе заводятся демо-данные с ключами,
вход: логин demo, пароль apistend2026.
docker compose up -d postgres
pnpm install
cp .env.example .env
pnpm db:migrate
pnpm db:seed
pnpm dev
В контейнере остаётся только база, остальное работает из исходников: правки подхватываются на лету, без пересборки образа.
Проверить, что шлюз жив, можно без всякого ключа:
curl -s localhost:8080/health
{"ok":true,"services":["bitrix24","ozon","wildberries"],"methods":2421,"memoryMb":178}
Поле methods — это то, сколько записей сейчас в каталоге вашего стенда; оно
меняется с каждой волной пополнения, поэтому и приходит из базы, а не из текста.
Ответ /health длиннее показанного: в нём ещё счётчики кешей, доля выборки
журнала и срок хранения логов.
Про JWT_SECRET
Значение JWT_SECRET в .env.example помечено как dev-only-change-me.
Этим же секретом подписываются хеши ключей доступа, так что для любого стенда,
до которого можно достучаться не с вашей машины, замените его:
openssl rand -base64 32.
Шаг 2. Заведите аккаунт
Регистрация — логин и пароль от восьми символов; входа через сторонние провайдеры нет. Почта необязательна и на вход не влияет: писем сервис не шлёт, восстановления пароля по ней нет. Имя и название проекта тоже необязательны: без имени подписью служит логин, без проекта — «Первый проект».
Логин — латиница, цифры, точка, дефис и подчёркивание, от 3 до 40 символов.
Регистр не важен: Ivan и ivan — один и тот же аккаунт.
Проще всего зарегистрироваться в кабинете на localhost:3100/register. То же
самое из терминала:
curl -s -X POST localhost:8080/api/auth/register \
-H 'Content-Type: application/json' \
-d '{"login":"you","password":"apistend2026","project":"Интеграция 1С"}'
{
"user": {"id":"cmttxymew0007…","login":"you","email":null,"name":"You","initials":"Y"},
"sandbox": {"id":"cmttxymf70008…","name":"sandbox-01","project":"Интеграция 1С"},
"apiKey": "stend_sbx_732e…"
}
Регистрация сразу заводит песочницу sandbox-01 и в ней ключ «Первый ключ»
на все сервисы стенда: без них продуктом нельзя пользоваться, поэтому отдельного
шага «создайте песочницу» нет.
Ключ показывается один раз
В базе лежит только хеш ключа и его края — начало и хвост для маски
stend_sbx_732e••••••e8c7. Поле apiKey в ответе на регистрацию и поле secret
в ответе на создание ключа — единственные моменты, когда полное значение покидает
сервер. Не сохранили — заведите новый ключ, восстановить существующий нельзя.
Шаг 3. Создайте свой ключ (необязательно)
Ключ из регистрации уже работает. Отдельный ключ имеет смысл заводить под конкретный сервис или конкретную интеграцию — тогда чужой код не сможет ходить туда, куда ему не надо:
curl -s -X POST localhost:8080/api/keys \
-b cookies.txt -H 'Content-Type: application/json' \
-d '{"name":"Проверка документации","kind":"sandbox","services":["wildberries"]}'
{
"key": {"id":"cmtty1kse003p…","name":"Проверка документации","mask":"stend_sbx_b47e••••••fa66"},
"secret": "stend_sbx_b47e…",
"warning": "Сохраните ключ: полностью он показывается только сейчас"
}
То же самое делает кнопка «Создать ключ» на экране «Ключи и токены» в кабинете —
запрос ходит с cookie сессии, поэтому в curl нужен -b cookies.txt (сохранить
её можно флагом -c cookies.txt при регистрации или входе).
Что задаётся у ключа
Незнакомый или отозванный ключ отвечает 401 в родном конверте сервиса, а причину кладёт в служебный заголовок:
HTTP/1.1 401 Unauthorized
x-apistend-error: key-unknown-or-revoked
{"error":"NO_AUTH_FOUND","error_description":"Wrong authorization data"}
Шаг 4. Сделайте первый запрос
Подставьте адрес стенда вместо боевого. Ключ кладите туда же, куда его кладёт клиентская библиотека сервиса.
KEY=stend_sbx_…
curl -si localhost:8080/wb/api/v3/warehouses -H "Authorization: $KEY"
curl -si -X POST localhost:8080/oz/v3/posting/fbs/list \
-H "Client-Id: 123" -H "Api-Key: $KEY" \
-H 'Content-Type: application/json' -d '{}'
curl -si localhost:8080/b24/rest/crm.deal.list -H "X-Mock-Key: $KEY"
У Bitrix24 работает и родная адресация входящего вебхука —
localhost:8080/rest/1/$KEY/crm.deal.list.json, и параметр auth=.
Живой ответ на первую из этих команд:
HTTP/1.1 200 OK
access-control-allow-origin: *
content-type: application/json
x-request-id: fd92ca05545b4fe9edcf61a7c1189c58
x-ratelimit-limit: 300
x-ratelimit-remaining: 299
x-ratelimit-reset: 1
x-apistend-request-id: fd92ca05545b4fe9edcf61a7c1189c58
x-apistend-source: schema
x-apistend-readiness: updating
x-apistend-scenario: success
x-apistend-upstream: https://marketplace-api.wildberries.ru
x-apistend-snapshot: 2026-09-07
x-apistend-cors: added-by-sandbox
[{"name":"ул. Троицкая, Подольск, Московская обл.","officeId":90414,"id":68574,
"cargoType":1,"deliveryType":1,"isDeleting":false,"isProcessing":true}, …]
Верхняя половина — заголовки самого Wildberries: Content-Type без charset,
X-Request-Id из 32 знаков, счётчик лимита. Ровно это увидела бы ваша библиотека
в бою, и ровно поэтому подмена адреса её не ломает. У Ozon набор другой,
у Битрикс24 — третий.
Нижняя половина — X-APIStend-*: их в бою нет, они говорят, откуда взялось тело
и насколько готов мок этого метода. Здесь ответ собран по схеме, а не взят готовым
примером из спецификации.
Разбор всех заголовков — в разделе Заголовки ответа.
Шаг 5. Найдите вызов в журнале
Журнал открывается на экране «Логи» кабинета — localhost:3100/logs.
Искать удобно по X-APIStend-Request-Id из ответа: это и есть публичный
идентификатор записи, и у Wildberries с Ozon он совпадает с боевым заголовком
(X-Request-Id и x-o3-trace-id соответственно). Из терминала — тот же журнал, что видит кабинет:
curl -s -b cookies.txt 'localhost:8080/api/logs?limit=3'
{
"summary": {"total":15,"errorRate":33.33,"avgLatencyMs":211,"p95LatencyMs":1502},
"sampling": {"sampleRate":1,"sampledOut":0},
"rows": [
{"publicId":"fd92ca05545b4fe9edcf61a7c1189c58","serviceCode":"wildberries","httpMethod":"GET",
"endpoint":"/api/v3/warehouses","statusCode":200,"durationMs":5,"sizeBytes":721}
]
}
Тело успешного ответа в журнале не хранится: оно детерминировано и восстанавливается движком по методу и объёму демо-данных при открытии карточки запроса. Тела ошибок хранятся — в их конверте есть идентификатор запроса и метка времени, восстановить их неоткуда.
Проверьте сценарий ошибки
Ответ переключается заголовком X-Mock-Scenario. Значения — те же, что
в кабинете:
Значения X-Mock-Scenario
curl -si localhost:8080/wb/api/v3/warehouses \
-H "Authorization: $KEY" -H 'X-Mock-Scenario: rate_limit'
HTTP/1.1 429 Too Many Requests
content-type: application/json
x-request-id: 36170ddaa809e86093bdbecb84fd2482
x-ratelimit-limit: 300
x-ratelimit-remaining: 0
x-ratelimit-reset: 20
x-ratelimit-retry: 20
x-apistend-scenario: rate_limit
{"title":"Too Many Requests","detail":"rate limit exceeded","code":"TooManyRequests",
"requestId":"36170ddaa809e86093bdbecb84fd2482","origin":"ag-api","status":429,
"statusText":"too_many_requests","timestamp":"2026-09-09T10:14:24.992Z"}
Поле requestId в теле повторяет заголовок X-Request-Id — так же, как в бою.
Тот же сценарий у Bitrix24 даёт не 429, а 503 QUERY_LIMIT_EXCEEDED:
HTTP/1.1 503 Service Unavailable
{"error":"QUERY_LIMIT_EXCEEDED","error_description":"Too many requests"}
Мок повторяет поведение конкретного сервиса, а не общее представление о лимитах.
Подводные камни первых минут
- Новая песочница по умолчанию врёт в пяти процентах случаев. Доля случайных
ошибок у свежей песочницы — 5 %: примерно каждый двадцатый успешный запрос
подменяется на
server_error. Это настройка, а не сбой; поставьте её в ноль ползунком на экране «Ключи и токены» — или запросомPATCH /api/v1/sandboxes/{sandboxId}с{"errorRate": 0}, если сейчас проверяете не обработку сбоев. - Ответ приходит не мгновенно. Стандартная искусственная задержка песочницы —
250 мс. Фактическая равна минимуму из настройки песочницы и задержки самого
метода, а заголовок
X-Mock-Delay(0–3000 мс) перебивает обе. - Опечатка в имени сценария не ошибка. Неизвестное значение
X-Mock-Scenarioмолча трактуется какsuccess. Что именно отработало, всегда видно вX-APIStend-Scenarioответа. timeoutдержит соединение полминуты. Это не зависание стенда: сценарий так и задуман, ответ придёт через 30 секунд.- Опечатка в пути даёт родной 404 сервиса, но с подсказкой в служебном
заголовке:
x-apistend-did-you-mean: /api/v3/warehouses, /api/v3/warehouses/{warehouseId}, …