Мок-API

Заголовки ответа

Боевые заголовки каждого сервиса плюс собственные X-APIStend-* — что приходит, у кого чего нет и почему набор разный.

На этой странице · 6

Заголовки ответа делятся на две части, и это не формальность, а правило, по которому здесь всё устроено.

Боевые заголовки сервиса — те, что отдал бы настоящий Wildberries, Ozon или Битрикс24. Их набор у каждого свой, и APIStend повторяет его буквально: ничего не добавляет и ничего не убирает. Именно поэтому подмена базового адреса не ломает клиентскую библиотеку — она читает то же, что читала в бою.

Заголовки APIStend — всё, что начинается с X-APIStend-. Их в бою нет и быть не может; они отвечают на вопрос «откуда взялось это тело и насколько ему верить». Ни одна боевая библиотека их не читает, поэтому они ничего не ломают, а вам позволяют пользоваться моком осознанно.

Боевые заголовки: у каждого сервиса свои

Bitrix24Ozon Seller APIWildberriesApify
Content-Typeapplication/json; charset=utf-8application/jsonapplication/jsonapplication/json; charset=utf-8
Идентификатор запросанетx-o3-trace-id, 16 знаковX-Request-Id, 32 знаканет
Заголовки лимитанетнетX-Ratelimit-Limit, -Remaining, -Reset, -Retryтолько X-RateLimit-Limit
Остаток лимитав теле: time.operating_reset_atнигдев заголовкахнигде
CORS в боютолько порталузапрещённе отдаётсяразрешён всем

Разница в Content-Type не косметическая: Битрикс24 и Apify приходят с charset, Ozon и Wildberries — без него. Строгие клиенты это сравнивают.

Колонка Apify показывает третий вариант поведения с лимитом, которого до неё в стенде не было: сервис сообщает потолок, но не остаток. Клиент, написанный на чтении X-Ratelimit-Remaining, в бою получит undefined — и в моке получит его же. Вдобавок у Apify лимит зависит от эндпоинта, а не от сервиса: подробности в Лимитах.

Списковые ответы Apify дублируют конверт data в заголовки X-Apify-Pagination-Total, -Offset, -Count, -Limit, -Desc. Значения мок берёт из того самого тела, которое отдаёт, поэтому заголовок разойтись с телом не может — иначе листающий клиент ушёл бы в бесконечный цикл.

Идентификатор запроса у Wildberries продублирован в теле ошибки — поле requestId спецификация прямо называет копией заголовка X-Request-Id. У APIStend это одно и то же значение, и оно же лежит в журнале кабинета: разработчик приносит в поддержку то число, которое увидела его библиотека.

Живой ответ Wildberries:

HTTP/1.1 200 OK
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

Тот же вызов у Ozon — ни одного заголовка лимита, вместо x-request-id сквозной идентификатор платформы:

HTTP/1.1 200 OK
content-type: application/json
x-o3-trace-id: f0c9ea91aae8abf9
x-apistend-request-id: f0c9ea91aae8abf9
x-apistend-source: example
x-apistend-readiness: ready

А у Битрикс24 нет и его: портал не отдаёт идентификатора запроса вовсе, зато к каждому ответу прикладывает конверт time — с длительностью вызова и с operating_reset_at, по которому клиент судит об остатке ресурса.

Конверт time приходит всегда

Даже там, где в документации Битрикс24 его в примере нет. Библиотеки вроде bitrix24-php-sdk разбирают time как обязательное поле, и ответ без него уронил бы рабочую интеграцию на разборе. Значения в нём — настоящие: сколько шёл именно ваш вызов, а не переписанные из примера документации.

Заголовки APIStend

ЗаголовокЗначенияЧто означает
X-APIStend-Sourceexample, schema, genericоткуда взято тело
X-APIStend-Readinessready, updating, plannedготовность мока этого метода
X-APIStend-Scenarioзначение X-Mock-Scenarioкакой сценарий отработал
X-APIStend-Upstreamхост боевого сервисачто подменяет этот адрес
X-APIStend-Snapshotдата вида 2026-09-07на какую дату снята спецификация метода
X-APIStend-Request-Idreq_a50c51dbe8 или боевой идентификаторпо нему запрос ищется в журнале кабинета
X-APIStend-Corsadded-by-sandbox, nativenative — сервис и в бою разрешает браузер (так у Apify)
X-APIStend-Retry-Afterсекундырекомендуемая пауза там, где сервис её не сообщает

X-APIStend-Request-Id есть всегда — в том числе у Битрикс24, где боевого заголовка не существует. У Wildberries и Ozon он повторяет боевой.

Три яруса ответа

X-APIStend-Source — это ярус, на котором собрали тело.

ЗначениеКак собраноЧему можно верить
exampleпример ответа из документации сервисаи форме, и значениям — они из документации
schemaгенерация по схеме ответа + демо-данныеформе: набор полей и типы из спецификации, значения выдуманы
genericпустой, но валидный для сервиса конверттолько тому, что клиент не упадёт на разборе

Ярус связан с готовностью: example — ready, schema — updating, generic — planned. Так метод и помечен в каталоге.

Ответ метода без примера и без схемы у Bitrix24 выглядит буквально так (плюс конверт time, который портал добавляет всегда):

{"result":[],"total":0}

У Ozon в этом случае {"result":{}}, у Wildberries {}, у Apify {"data":{}} (он заворачивает в data каждый ответ, и голый {} уронил бы клиента не там, где тот ошибся). Метод с успешным кодом 204 отвечает пустым телом.

Зачем это в тестах

Тест, который проверяет разбор ответа, имеет право работать с любым ярусом. Тест, который проверяет бизнес-логику по значениям полей, на schema и generic проверяет выдуманные данные. Прочитайте X-APIStend-Source в тесте и пометьте такой случай явно, вместо того чтобы удивляться расхождению с боем.

Особые источники

Кроме трёх ярусов каталога, X-APIStend-Source принимает два значения, у которых другое происхождение:

  • custom-mock — ответ отдал ваш собственный мок по префиксу /custom/;
  • app-context — ответ про состояние портала Bitrix24 для локального приложения (app.info, placement.*, event.*). Такие ответы зависят от того, что приложение установило и зарегистрировало, а не от каталога. Рядом приходит X-APIStend-App с client_id приложения.

Заголовки на ошибках

ЗаголовокКогда приходит
X-APIStend-Errorключ не подошёл: key-missing, key-unknown-or-revoked
X-APIStend-Did-You-Meanпуть не найден: до трёх похожих путей каталога
X-APIStend-Scenarioсработал сценарий ошибки, в том числе timeout
X-APIStend-Retry-Afterпревышение лимита у Bitrix24 и Ozon — у них своего заголовка нет
X-Ratelimit-Retryпревышение лимита у Wildberries — это его боевой заголовок

Тело ошибки всегда остаётся родным конвертом сервиса, а причина отказа уходит в X-APIStend-Error: в бою такого поля нет, и подмешивать его в тело нельзя.

На ответе с ошибкой авторизации заголовков X-APIStend-Source, Readiness и Snapshot нет: метод до каталога не дошёл. Заголовков лимита там тоже нет — считать его не на чем, ключ не опознан.

Подводные камни

Браузер видит не все заголовки

Из кода страницы читаются только заголовки, перечисленные в Access-Control-Expose-Headers. Шлюз перечисляет там весь свой набор — боевые боевые заголовки всех сервисов и все x-apistend-*, — но это касается только запросов из браузера к песочнице. Боевые Ozon и Wildberries из браузера вызывать нельзя вовсе, так что код, который так делает, в бою не поедет.

  • Имена заголовков приходят в нижнем регистре; сравнивайте без учёта регистра.
  • Не пишите обработку лимита по заголовкам Wildberries для всех сервисов: у Ozon и Битрикс24 их нет вовсе, у Apify есть только потолок без остатка — см. Лимиты.
  • X-APIStend-Snapshot — дата снимка спецификации, а не дата ответа. У методов одного сервиса она общая.
  • X-APIStend-Upstream показывает реальный хост метода. У Wildberries это не один адрес: marketplace-api, content-api, advert-api и другие.