{
  "info": {
    "name": "SpikePC — Partner API (API keys)",
    "_postman_id": "spikepc-partner-api-v1",
    "description": "Проверка партнёрского API организации SpikePC (обмен по API-ключу владельца клуба).\n\nПЕРЕД ЗАПУСКОМ:\n  • api_key  — впишите ключ из раздела «API-ключи» панели организации (он один обязателен);\n  • base_url — АДРЕС ТОЧКИ ВХОДА ЦЕЛИКОМ, со слэшем на конце: https://spikepc.com/spike_api/\n               Слэш обязателен — без него веб-сервер отвечает редиректом и тело POST теряется;\n  • club_id  — id клуба организации (по умолчанию 1). Его отдаёт запрос club.list.\n\nОстальные переменные (gs_id, gs_mac, product_id, client_id, session_id, order_id,\nchat_session_id) заполняются сами: списки запоминают id первого элемента, поэтому Runner\nпроходит коллекцию целиком без ручного ввода. club_id НЕ перезаписывается — он ваш.\n\nВАЖНО: папки 1–7 ждут ответа 200, то есть рассчитаны на ключ с ПОЛНЫМ доступом. Ключ с\nурезанными правами законно отвечает 403 forbidden_action на недоступные ему действия — это\nне ошибка сервиса; что доступно ключу, говорит meta.actions. Папка 8 проверяет сами отказы.\n\nКонтракт целиком — https://spikepc.com/dev/partner_api.html\n\nПАПКА 9 МЕНЯЕТ ДАННЫЕ (деньги, заказы, брони, команды станциям) — она намеренно\nпоследняя и не рассчитана на прогон Runner'ом: запускайте её запросы поштучно и на\nтестовой организации.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://spikepc.com/spike_api/",
      "type": "string"
    },
    {
      "key": "api_key",
      "value": "",
      "type": "string"
    },
    {
      "key": "club_id",
      "value": "1",
      "type": "string"
    },
    {
      "key": "gs_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "gs_mac",
      "value": "",
      "type": "string"
    },
    {
      "key": "product_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "barcode",
      "value": "",
      "type": "string"
    },
    {
      "key": "client_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "session_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "order_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "chat_session_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "payment_method_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "ticket_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "tx_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "reserve_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "discount_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "postpay_id",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "1. Ключ",
      "description": "Действия без права: проверка ключа и самоописание.",
      "item": [
        {
          "name": "ping — ключ принят",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"ping\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Организация, имя ключа, область доступа, срок (пусто = бессрочно), время сервера."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('ping');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('организация пришла', function () { pm.expect(j.data.org_id).to.be.a('number'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "meta.actions — что доступно ключу",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"meta.actions\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Список действий, разрешённых ЭТОМУ ключу. Нет нужного — владелец отмечает право в карточке ключа."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('meta.actions');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "2. Клуб и зал",
      "description": "Клубы, схема зала, станции и их живое состояние.",
      "item": [
        {
          "name": "club.list — клубы организации",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"club.list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Клубы ключа: название, адрес, телефоны, координаты. Первый запоминается в club_id. Переменная club_id задаётся вручную в окружении — этот запрос её не перезаписывает."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('club.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "gs_group.list — группы станций",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs_group.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Группы станций: на них держатся тарифная сетка и абонементы."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('gs_group.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "club.map — схема зала",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"club.map\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Схема зала как её хранит панель (объект либо null, если карта ещё не нарисована)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('club.map');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('есть поле map', function () { pm.expect(j.data).to.include.keys('club_id','name','map'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "gs.list — станции клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Станции страницей. Первая запоминается в gs_id и gs_mac."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('gs.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});",
                  "if (j.data.items.length) { pm.collectionVariables.set('gs_id', j.data.items[0].id); }",
                  "if (j.data.items.length) { pm.collectionVariables.set('gs_mac', j.data.items[0].mac); }"
                ]
              }
            }
          ]
        },
        {
          "name": "gs.get — станция по id",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.get\",\n  \"data\": {\n    \"id\": \"{{gs_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Одна станция по нашему id."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('gs.get');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('вернулась одна запись', function () { pm.expect(j.data.item).to.be.an('object'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "gs.get — станция по MAC",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.get\",\n  \"data\": {\n    \"mac\": \"{{gs_mac}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Та же станция по MAC — партнёр чаще знает его, а не наш id."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('gs.get');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('вернулась одна запись', function () { pm.expect(j.data.item).to.be.an('object'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "gs.status — живое состояние зала",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.status\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Связь, занятость клиентом, режим станции, остаток оплаченного времени — те же цифры, что у оператора на карте."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('gs.status');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "snap.list — золотые образы клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"snap.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Зеркало образов клубного сервера: какой активен, когда снят."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('snap.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "3. Каталог",
      "description": "Игры, жанры, баннеры, товары и склад. `locale` подменяет названия переводом.",
      "item": [
        {
          "name": "game.list — игры клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"game.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"limit\": 5,\n    \"locale\": \"uk\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Фильтры: club_id, genre_id, status, search. У каждой игры — способ запуска и жанры."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('game.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "game_genre.list — жанры",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"game_genre.list\",\n  \"data\": {\n    \"locale\": \"uk\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Справочник жанров организации (клуба в нём нет — список один на сеть)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('game_genre.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "banner.list — баннеры клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"banner.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Область показа на экране станции, период, окно времени, активность."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('banner.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "category.list — группы товаров",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"category.list\",\n  \"data\": {\n    \"locale\": \"uk\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Группы товаров организации."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('category.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "product.list — товары клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"product.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"limit\": 5,\n    \"locale\": \"uk\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "club_id обязателен: цена у товара своя в каждом клубе. Поиск search — по названию, артикулу и штрихкоду."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('product.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});",
                  "if (j.data.items.length) { pm.collectionVariables.set('product_id', j.data.items[0].id); }",
                  "if (j.data.items.length) { pm.collectionVariables.set('barcode', j.data.items[0].barcode || ''); }"
                ]
              }
            }
          ]
        },
        {
          "name": "product.get — товар по id",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"product.get\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"id\": \"{{product_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Один товар по id, артикулу (code) или штрихкоду (barcode)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('product.get');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('вернулась одна запись', function () { pm.expect(j.data.item).to.be.an('object'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "stock.list — движение склада",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"stock.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Приход, списание, продажа, возврат, корректировка. qty со знаком, поэтому сумма сходится с остатком."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('stock.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "4. Тарификация",
      "description": "Тарифы и абонементы с недельными сетками, скидки, промокоды, кассы.",
      "item": [
        {
          "name": "tariff.list — тарифы клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"tariff.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Цена за час, цвет, действуют ли скидки клиента."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('tariff.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "tariff.schedule — сетка тарифов",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"tariff.schedule\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Интервалы «день+время → группа станций → тариф». Границы включительные, time_end — последняя включённая секунда."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('tariff.schedule');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "ticket.list — абонементы клуба",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"ticket.list\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Фиксированное время за фиксированную цену; auto_apply — включается ли без вопроса клиенту."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('ticket.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "ticket.schedule — когда ПРОДАЁТСЯ",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"ticket.schedule\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"kind\": \"sale\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Сетка продажи абонемента (kind=sale, по умолчанию)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('ticket.schedule');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "ticket.schedule — когда ДЕЙСТВУЕТ",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"ticket.schedule\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"kind\": \"valid\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Сетка расходования купленного абонемента. Пустая = действует всегда."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('ticket.schedule');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "discount.list — скидки",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"discount.list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Справочник ситуативных скидок (поводы, которые выдаёт оператор)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('discount.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "promocode.list — промокоды",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"promocode.list\",\n  \"data\": {\n    \"limit\": 10\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Событие, действие, сумма, окно и остаток активаций."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('promocode.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "payment_method.list — кассы",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"payment_method.list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Кассы организации. balance — вычисляемый итог движений; у бонусной кассы null (это не живые деньги)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('payment_method.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "5. Клиенты и деньги",
      "description": "Клиенты, их абонементы, леджер операций, смены и постоплаты.",
      "item": [
        {
          "name": "client.list — клиенты",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"client.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Поиск search — по почте, телефону, логину, имени и фамилии. Гостевые записи станций исключены."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('client.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});",
                  "if (j.data.items.length) { pm.collectionVariables.set('client_id', j.data.items[0].id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "client.get — карточка клиента",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"client.get\",\n  \"data\": {\n    \"id\": \"{{client_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "По id, email или phone (телефон ищется во всех форматах записи). Вместе с карточкой — его абонементы."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('client.get');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('вернулась одна запись', function () { pm.expect(j.data.item).to.be.an('object'); });",
                  "pm.test('абонементы приложены', function () { pm.expect(j.data).to.include.keys('packs'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "client.packs — абонементы клиента",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"client.packs\",\n  \"data\": {\n    \"id\": \"{{client_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Живые абонементы: остаток считается по стенным часам, поэтому не показывает сгоревшее время."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('client.packs');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "transaction.list — операции",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"transaction.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Леджер: пополнения, списания за время и товары, покупки абонементов, возвраты. discount_percent — под какой скидкой прошло списание."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('transaction.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "shift.list — кассовые смены",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"shift.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Кто открыл, сколько наличных на начало, принято по типам касс, «должно быть» и расхождение у закрытой смены."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('shift.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "postpay.list — постоплаты",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"postpay.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Время копится к оплате вместо списания с баланса: armed → active → awaiting_payment → paid."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('postpay.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "6. Сессии, заказы, брони, чат",
      "description": "История игры, заказы магазина, календарь броней, переписка с клиентами.",
      "item": [
        {
          "name": "session.list — сессии",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"session.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Фильтры: club_id, gs_id, client_id, status, период. У активной сессии итог ещё копится — поле active."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('session.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});",
                  "if (j.data.items.length) { pm.collectionVariables.set('session_id', j.data.items[0].id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "session.get — сессия с событиями",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"session.get\",\n  \"data\": {\n    \"id\": \"{{session_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Одна сессия плюс журнал: старт, запуски игр, заказы, конец."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('session.get');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('вернулась одна запись', function () { pm.expect(j.data.item).to.be.an('object'); });",
                  "pm.test('события приложены', function () { pm.expect(j.data).to.include.keys('events'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "order.list — заказы магазина",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"order.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Заказы со станций вместе с позициями. Заказ баланс не списывает — его платят на месте персоналу."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('order.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});",
                  "if (j.data.items.length) { pm.collectionVariables.set('order_id', j.data.items[0].id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "order.get — заказ с позициями",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"order.get\",\n  \"data\": {\n    \"id\": \"{{order_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Один заказ; у позиции комбо-набора в options лежит выбор клиента."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('order.get');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('вернулась одна запись', function () { pm.expect(j.data.item).to.be.an('object'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "reserve.list — брони станций",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"reserve.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Период считается ПО ПЕРЕСЕЧЕНИЮ: бронь, начавшаяся вчера и идущая сейчас, попадёт в выборку за сегодня."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('reserve.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "chat.list — диалоги",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"chat.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Один диалог = одна клиентская сессия за станцией. total — число диалогов, а не сообщений."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('chat.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});",
                  "if (j.data.items.length) { pm.collectionVariables.set('chat_session_id', j.data.items[0].session_id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "chat.messages — сообщения диалога",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"chat.messages\",\n  \"data\": {\n    \"session_id\": \"{{chat_session_id}}\",\n    \"limit\": 50\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Сообщения одной сессии в хронологическом порядке; direction in — от клиента, out — от оператора."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('chat.messages');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "7. Организация",
      "description": "Настройки, языки, сотрудники, журнал изменений, предрасчитанная аналитика.",
      "item": [
        {
          "name": "org.info — организация и настройки",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"org.info\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Часовой пояс, правила склада, лимиты абонементов и постоплаты, клубы с приёмом заказов. Реквизиты и токены наружу не отдаются."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('org.info');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('настройки и клубы пришли', function () { pm.expect(j.data).to.include.keys('settings','clubs','timezone'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "locale.list — языки организации",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"locale.list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Коды языков каталога; is_default — язык по умолчанию."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('locale.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "staff.list — сотрудники",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"staff.list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Сотрудники и их клубы. Пароли и контакты учётки панели не отдаются."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('staff.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "event.list — журнал изменений",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"event.list\",\n  \"data\": {\n    \"limit\": 5\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Кто и что менял в панели. Полные снимки «до/после» наружу не отдаются."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('event.list');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "analytics.daily — аналитика по дням",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"analytics.daily\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Предрасчёт ночного крона: занятость и выручка времени по группам плюс выручка магазина. Текущий день обычно пуст — за сегодня смотрите живые действия."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j).to.have.all.keys('code', 'error_key', 'error_text', 'action', 'data');",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('analytics.daily');",
                  "});",
                  "pm.test('data — объект, а не массив', function () { pm.expect(j.data).to.be.an('object'); });",
                  "pm.test('список с полем total', function () {",
                  "    pm.expect(j.data.items).to.be.an('array');",
                  "    pm.expect(j.data).to.include.keys('total');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "8. Отказы",
      "description": "Сервис отказывает понятно: по error_key партнёр различает причины.",
      "item": [
        {
          "name": "без ключа → 401 empty_key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}",
                "disabled": true
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"ping\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Заголовок X-Api-Key отключён."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 401', function () { pm.response.to.have.status(401); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = empty_key', function () {",
                  "    pm.expect(j.code).to.eql(401);",
                  "    pm.expect(j.error_key).to.eql('empty_key');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "чужой ключ → 401 unknown_key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}",
                "disabled": true
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"ping\",\n  \"api_key\": \"0000deadbeef0000\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Ключ передан в теле (так тоже можно), но такого ключа нет."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 401', function () { pm.response.to.have.status(401); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = unknown_key', function () {",
                  "    pm.expect(j.code).to.eql(401);",
                  "    pm.expect(j.error_key).to.eql('unknown_key');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "неизвестное действие → 404 unknown_action",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.explode\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Опечатка в имени действия."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 404', function () { pm.response.to.have.status(404); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = unknown_action', function () {",
                  "    pm.expect(j.code).to.eql(404);",
                  "    pm.expect(j.error_key).to.eql('unknown_action');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "нет обязательного параметра → 422 bad_params",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.get\",\n  \"data\": {}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "gs.get требует id либо mac."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 422', function () { pm.response.to.have.status(422); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = bad_params', function () {",
                  "    pm.expect(j.code).to.eql(422);",
                  "    pm.expect(j.error_key).to.eql('bad_params');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "товары без клуба → 422 bad_params",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"product.list\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "У товара своя цена в каждом клубе, поэтому club_id обязателен."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 422', function () { pm.response.to.have.status(422); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = bad_params', function () {",
                  "    pm.expect(j.code).to.eql(422);",
                  "    pm.expect(j.error_key).to.eql('bad_params');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "чужой клуб → 403 club_foreign",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"club.map\",\n  \"data\": {\n    \"club_id\": 999999\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Организация берётся из ключа, подменить её нельзя."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 403', function () { pm.response.to.have.status(403); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = club_foreign', function () {",
                  "    pm.expect(j.code).to.eql(403);",
                  "    pm.expect(j.error_key).to.eql('club_foreign');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "чужое значение фильтра → 422 bad_params",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"order.list\",\n  \"data\": {\n    \"status\": \"выдуманный\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Значения фильтров сверяются с белым списком, а не игнорируются молча."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 422', function () { pm.response.to.have.status(422); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = bad_params', function () {",
                  "    pm.expect(j.code).to.eql(422);",
                  "    pm.expect(j.error_key).to.eql('bad_params');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "тело не JSON → 400 bad_request",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "это не json",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "В теле не JSON-объект."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 400', function () { pm.response.to.have.status(400); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = bad_request', function () {",
                  "    pm.expect(j.code).to.eql(400);",
                  "    pm.expect(j.error_key).to.eql('bad_request');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "9. Запись — МЕНЯЕТ ДАННЫЕ",
      "description": "Эти запросы ИЗМЕНЯЮТ данные клуба: принимают деньги, продают абонемент, двигают заказ, создают бронь, выдают скидку и кредит, шлют команды станции. Запускайте их поштучно и на тестовой организации, а не Runner'ом по всей коллекции.\n\nПеред запуском заполните переменные: client_id (его отдаёт client.list), payment_method_id (payment_method.list), ticket_id (ticket.list), order_id (order.list), gs_id (gs.list), discount_id (discount.list). Для денег нужна ОТКРЫТАЯ кассовая смена в клубе.",
      "item": [
        {
          "name": "client.topup — пополнить баланс",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"client.topup\",\n  \"data\": {\n    \"client_id\": \"{{client_id}}\",\n    \"amount\": 100,\n    \"payment_method_id\": \"{{payment_method_id}}\",\n    \"club_id\": \"{{club_id}}\",\n    \"comment\": \"оплата у стойки\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Касса обязательна; для бонусной кассы обязателен комментарий. Без открытой смены — 409 no_shift."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('client.topup');",
                  "});",
                  "pm.test('баланс вырос', function () { pm.expect(j.data.balance).to.be.above(j.data.balance_before - 0.001); });",
                  "if (j.data.tx_id) { pm.collectionVariables.set('tx_id', j.data.tx_id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "client.topup — сумма 0 → 422",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"client.topup\",\n  \"data\": {\n    \"client_id\": \"{{client_id}}\",\n    \"amount\": 0,\n    \"payment_method_id\": \"{{payment_method_id}}\",\n    \"club_id\": \"{{club_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Проверка отказа: сумма должна быть больше нуля."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 422', function () { pm.response.to.have.status(422); });",
                  "var j = pm.response.json();",
                  "pm.test('ключ ошибки = bad_amount', function () { pm.expect(j.error_key).to.eql('bad_amount'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "transaction.refund — вернуть пополнение",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"transaction.refund\",\n  \"data\": {\n    \"tx_id\": \"{{tx_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Возврат пополнения: сумма списывается обратно (можно в минус), исходная операция помечается возвращённой."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('transaction.refund');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "client.sell_ticket — продать абонемент",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"client.sell_ticket\",\n  \"data\": {\n    \"client_id\": \"{{client_id}}\",\n    \"ticket_id\": \"{{ticket_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Списывается с баланса клиента со его перманентной скидкой; пакет кладётся в запас, часы стартуют при активации на станции."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('client.sell_ticket');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "order.set_status — передвинуть заказ",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"order.set_status\",\n  \"data\": {\n    \"order_id\": \"{{order_id}}\",\n    \"status\": \"processing\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "new → processing → done, либо cancelled. Отмена возвращает товар на склад и НЕ возвращает деньги."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('order.set_status');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "reserve.create — создать бронь",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"reserve.create\",\n  \"data\": {\n    \"club_id\": \"{{club_id}}\",\n    \"gs_id\": \"{{gs_id}}\",\n    \"date_start\": \"2026-12-31 18:00:00\",\n    \"date_end\": \"2026-12-31 20:00:00\",\n    \"client_id\": \"{{client_id}}\",\n    \"description\": \"бронь из интеграции\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Проверки: окно клуба, пересечение с чужой бронью, горизонт 30 дней, длительность 30 минут…12 часов. Даты в примере поправьте на будущие."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('reserve.create');",
                  "});",
                  "if (j.data.reserve_id) { pm.collectionVariables.set('reserve_id', j.data.reserve_id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "reserve.cancel — снять бронь",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"reserve.cancel\",\n  \"data\": {\n    \"reserve_id\": \"{{reserve_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Снимает бронь, созданную предыдущим запросом."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('reserve.cancel');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "discount.grant — выдать скидку",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"discount.grant\",\n  \"data\": {\n    \"gs_id\": \"{{gs_id}}\",\n    \"discount_id\": \"{{discount_id}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "За станцией клиент — скидка идёт в его сессию; станция свободна — заявка ждёт входа 30 минут. discount_id: 0 снимает."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('discount.grant');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "credit.set — дать кредит на сессию",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"credit.set\",\n  \"data\": {\n    \"gs_id\": \"{{gs_id}}\",\n    \"amount\": 100\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Разрешённая глубина минуса до конца сессии; 0 снимает. Деньги на баланс не зачисляются. Нужна активная клиентская сессия."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('credit.set');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "postpay.enable — включить постоплату",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"postpay.enable\",\n  \"data\": {\n    \"gs_id\": \"{{gs_id}}\",\n    \"limit\": 300,\n    \"comment\": \"постоплата из интеграции\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Время копится к оплате вместо списания с баланса. `guest: true` — гостю без учётной записи."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('postpay.enable');",
                  "});",
                  "if (j.data.postpay_id) { pm.collectionVariables.set('postpay_id', j.data.postpay_id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "postpay.limit — изменить лимит",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"postpay.limit\",\n  \"data\": {\n    \"postpay_id\": \"{{postpay_id}}\",\n    \"limit\": 500\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Ниже уже начисленного лимит не ставится; пусто — снять лимит."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('postpay.limit');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "postpay.pay — принять оплату",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"postpay.pay\",\n  \"data\": {\n    \"postpay_id\": \"{{postpay_id}}\",\n    \"payment_method_id\": \"{{payment_method_id}}\",\n    \"comment\": \"оплата постоплаты\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Нужна открытая смена: деньги принимает смена. Пишет две строки леджера — приход в кассу и списание за время."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('postpay.pay');",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "gs.command — сообщение на станцию",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "X-Api-Key",
                "value": "{{api_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"action\": \"gs.command\",\n  \"data\": {\n    \"gs_id\": \"{{gs_id}}\",\n    \"action\": \"message\",\n    \"data\": {\n      \"text\": \"Ваше время заканчивается\",\n      \"duration\": 15\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}"
            },
            "description": "Разрешены message, poweroff, poweron, session_end. В ответе delivery: done/delivered — станция приняла, offline — не на связи, timeout — не ответила."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('HTTP 200', function () { pm.response.to.have.status(200); });",
                  "var j = pm.response.json();",
                  "pm.test('конверт ответа на месте', function () {",
                  "    pm.expect(j.code).to.eql(200);",
                  "    pm.expect(j.error_key).to.eql('');",
                  "    pm.expect(j.action).to.eql('gs.command');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
