{
  "info": {
    "_postman_id": "b64253ce-5444-4314-a89c-4e29c8773455",
    "name": "Hyran Data V1",
    "description": "Production-safe examples for the tenant-scoped Hyran Data REST and MCP APIs. Set api_token as a secret in the selected Postman environment. Never share or export a populated environment.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{api_token}}", "type": "string" }]
  },
  "event": [
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "pm.test('No unexpected server error', function () { pm.expect(pm.response.code).to.be.below(500); });",
          "pm.test('Region header is present', function () { pm.expect(pm.response.headers.get('X-Hyran-Data-Region')).to.exist; });",
          "pm.test('Request ID is a UUID', function () { pm.expect(pm.response.headers.get('X-Request-ID')).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i); });"
        ]
      }
    }
  ],
  "item": [
    {
      "name": "Service",
      "item": [
        {
          "name": "Liveness",
          "request": {
            "auth": { "type": "noauth" },
            "method": "GET",
            "url": "{{base_url}}/health/live",
            "description": "Process-only health check. This does not prove database readiness."
          }
        },
        {
          "name": "Readiness",
          "request": {
            "auth": { "type": "noauth" },
            "method": "GET",
            "url": "{{base_url}}/health/ready",
            "description": "Checks both the API process and its database connection."
          }
        },
        {
          "name": "OpenAPI 3.1",
          "request": {
            "auth": { "type": "noauth" },
            "method": "GET",
            "url": "{{base_url}}/openapi.json"
          }
        },
        {
          "name": "Authentication fails closed",
          "request": {
            "auth": { "type": "noauth" },
            "method": "GET",
            "url": "{{base_url}}/v1/entities",
            "description": "Expected response: 401 application/problem+json."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Missing token is rejected', function () { pm.response.to.have.status(401); });",
                  "pm.test('Uses problem details', function () { pm.expect(pm.response.headers.get('Content-Type')).to.include('application/problem+json'); });",
                  "pm.test('Returns a Bearer challenge', function () { pm.expect(pm.response.headers.get('WWW-Authenticate')).to.include('Bearer realm=\"hyran-data\"'); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Entity graph",
      "item": [
        {
          "name": "List entity types",
          "request": { "method": "GET", "url": "{{base_url}}/v1/entity-types" }
        },
        {
          "name": "Search entities",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/v1/entities?limit=100&type=sku&q=",
              "host": ["{{base_url}}"],
              "path": ["v1", "entities"],
              "query": [
                { "key": "limit", "value": "100" },
                { "key": "type", "value": "sku" },
                { "key": "q", "value": "", "disabled": true },
                { "key": "cursor", "value": "", "disabled": true }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code === 200) { const body = pm.response.json(); if (body.data.length) pm.environment.set('entity_id', body.data[0].entityId); }"
                ]
              }
            }
          ]
        },
        {
          "name": "Get entity",
          "request": { "method": "GET", "url": "{{base_url}}/v1/entities/{{entity_id}}" }
        },
        {
          "name": "Traverse relationships",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/v1/entities/{{entity_id}}/relationships?limit=100"
          }
        }
      ]
    },
    {
      "name": "BOM history",
      "item": [
        {
          "name": "List snapshots",
          "request": { "method": "GET", "url": "{{base_url}}/v1/bom/snapshots?limit=100" },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code === 200) { const rows = pm.response.json().data; if (rows.length) { pm.environment.set('snapshot_id', rows[0].snapshotId); pm.environment.set('to_snapshot_id', rows[0].snapshotId); } if (rows.length > 1) pm.environment.set('from_snapshot_id', rows[1].snapshotId); }"
                ]
              }
            }
          ]
        },
        {
          "name": "List yields for snapshot",
          "request": {
            "method": "GET",
            "url": "{{base_url}}/v1/bom/yields?snapshotId={{snapshot_id}}&limit=100"
          }
        },
        {
          "name": "Compare snapshots",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/v1/bom/yield-changes?fromSnapshotId={{from_snapshot_id}}&toSnapshotId={{to_snapshot_id}}&limit=100",
              "host": ["{{base_url}}"],
              "path": ["v1", "bom", "yield-changes"],
              "query": [
                { "key": "fromSnapshotId", "value": "{{from_snapshot_id}}" },
                { "key": "toSnapshotId", "value": "{{to_snapshot_id}}" },
                { "key": "limit", "value": "100" },
                { "key": "sku", "value": "", "disabled": true },
                { "key": "style", "value": "", "disabled": true },
                { "key": "mpn", "value": "", "disabled": true },
                { "key": "supplier", "value": "", "disabled": true },
                { "key": "changeType", "value": "changed", "disabled": true },
                { "key": "includeUnchanged", "value": "false", "disabled": true },
                { "key": "cursor", "value": "", "disabled": true }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Exports",
      "item": [
        {
          "name": "Create CSV export",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"format\": \"csv\",\n  \"resource\": \"bom_yield_changes\",\n  \"query\": {\n    \"fromSnapshotId\": \"{{from_snapshot_id}}\",\n    \"toSnapshotId\": \"{{to_snapshot_id}}\",\n    \"includeUnchanged\": false\n  }\n}"
            },
            "url": "{{base_url}}/v1/exports"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Export is accepted', function () { pm.response.to.have.status(202); });",
                  "if (pm.response.code === 202) pm.environment.set('export_id', pm.response.json().data.exportId);"
                ]
              }
            }
          ]
        },
        {
          "name": "Get export status",
          "request": { "method": "GET", "url": "{{base_url}}/v1/exports/{{export_id}}" }
        },
        {
          "name": "Download completed export",
          "request": { "method": "GET", "url": "{{base_url}}/v1/exports/{{export_id}}/download" },
          "description": "Run after the export status becomes completed and before its download window expires."
        }
      ]
    },
    {
      "name": "MCP",
      "item": [
        {
          "name": "Initialize",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Accept", "value": "application/json, text/event-stream" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"id\": 1,\n  \"method\": \"initialize\",\n  \"params\": {\n    \"protocolVersion\": \"2025-06-18\",\n    \"capabilities\": {},\n    \"clientInfo\": { \"name\": \"postman\", \"version\": \"1.0.0\" }\n  }\n}"
            },
            "url": "{{base_url}}/mcp"
          }
        },
        {
          "name": "List tools",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Accept", "value": "application/json, text/event-stream" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"id\": 2,\n  \"method\": \"tools/list\",\n  \"params\": {}\n}"
            },
            "url": "{{base_url}}/mcp"
          }
        },
        {
          "name": "Call search_entities",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Accept", "value": "application/json, text/event-stream" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"id\": 3,\n  \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"search_entities\",\n    \"arguments\": { \"type\": \"sku\", \"limit\": 25 }\n  }\n}"
            },
            "url": "{{base_url}}/mcp"
          }
        },
        {
          "name": "Call get_bom_yield_changes",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Accept", "value": "application/json, text/event-stream" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"id\": 4,\n  \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"get_bom_yield_changes\",\n    \"arguments\": {\n      \"fromSnapshotId\": \"{{from_snapshot_id}}\",\n      \"toSnapshotId\": \"{{to_snapshot_id}}\",\n      \"limit\": 25\n    }\n  }\n}"
            },
            "url": "{{base_url}}/mcp"
          }
        }
      ]
    }
  ]
}
