{
  "info": {
    "_postman_id": "0b3e3306-7b9c-461f-bce3-add160e6a45e",
    "name": "DocImprint API",
    "description": "Customer-facing DocImprint API collection. Set BASE_URL and API_KEY in collection variables before running.\n\nAuthenticated requests use collection-level `Authorization: Bearer {{API_KEY}}`. Discovery endpoints override auth to noauth.\n\n**Default behaviour:** `POST /v1/extract` returns a lean AI extraction with no stored bundle (`store: false`). Add `\"store\": true` to the request body (or `?store=true`) to create a verifiable evidence bundle with `bundle_id`, artifacts, and provenance.\n\n**Browser content cache:** Add `?max_age=<seconds>` to reuse a recently-fetched page's raw content (browser/OCR skip on hit, AI always runs fresh).\n\nDocs: https://docimprint.com/docs",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{API_KEY}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "/**",
          " * Pre-request: inject Bearer API_KEY for authenticated requests.",
          " * Skips injection when the request uses auth: noauth.",
          " */",
          ";(async () => {",
          "  const authType = pm.request.auth?.type",
          "  if (authType === 'noauth') return",
          "",
          "  const apiKey = pm.collectionVariables.get('API_KEY') || pm.environment.get('API_KEY')",
          "  if (!apiKey || !String(apiKey).trim()) {",
          "    console.warn('[postman] API_KEY is empty — set dr_live_... in collection or environment variables')",
          "    return",
          "  }",
          "  pm.request.headers.upsert({ key: 'Authorization', value: `Bearer ${String(apiKey).trim()}` })",
          "})()",
          ""
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "BASE_URL",
      "value": "https://api.docimprint.com",
      "type": "string",
      "description": "API base URL (default: production)"
    },
    {
      "key": "API_KEY",
      "value": "",
      "type": "secret",
      "description": "Bearer dr_live_... — get one at docimprint.com/get-started"
    },
    {
      "key": "TARGET_URL",
      "value": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
      "type": "string",
      "description": "URL to analyse in examples"
    },
    {
      "key": "BUNDLE_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by full extract"
    },
    {
      "key": "RECEIPT_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by GET /receipts if any signed action receipts exist (created via MCP tool calls)"
    },
    {
      "key": "PREV_BUNDLE_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by compare extract (internal)"
    },
    {
      "key": "INVOICE_BUNDLE_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by invoice evidence bundle extract"
    },
    {
      "key": "COLLECTION_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by collection create"
    },
    {
      "key": "MONITOR_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by monitor create"
    },
    {
      "key": "MONITOR_ALWAYS_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by monitor create (mode=always)"
    },
    {
      "key": "JOB_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by async / index steps"
    },
    {
      "key": "DELETE_BUNDLE_ID",
      "value": "",
      "type": "string",
      "description": "Auto-set by throwaway delete step"
    },
    {
      "key": "WEBHOOK_URL",
      "value": "https://your-webhook.io/notify",
      "type": "string",
      "description": "HTTPS URL for monitor webhooks"
    },
    {
      "key": "SKIP_NOTARIZE",
      "value": "false",
      "type": "string",
      "description": "Set true to skip on-chain notarize step"
    }
  ],
  "item": [
    {
      "name": "1 · Getting started",
      "item": [
        {
          "name": "GET / — health check",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                ""
              ]
            },
            "description": "Service health and version. No auth required.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('status field', () => { pm.expect(pm.response.json().status).to.eql('ok'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /.well-known/agent.json",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/.well-known/agent.json",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                ".well-known",
                "agent.json"
              ]
            },
            "description": "Machine-readable capabilities, pricing, and MCP endpoint. No auth required.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has name', () => { pm.expect(pm.response.json().name).to.eql('DocImprint'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /openapi.json",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/openapi.json",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "openapi.json"
              ]
            },
            "description": "OpenAPI 3 specification for the full API. No auth required.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has openapi field', () => { pm.expect(pm.response.json()).to.have.property('openapi'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /SKILL.md",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/SKILL.md",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "SKILL.md"
              ]
            },
            "description": "Agent onboarding guide (markdown). No auth required.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('is markdown', () => { pm.expect(pm.response.headers.get('content-type')).to.include('text'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /.well-known/darkroom-keys.json",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/.well-known/darkroom-keys.json",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                ".well-known",
                "darkroom-keys.json"
              ]
            },
            "description": "Published secp256k1 keys for offline manifest verification. No auth required.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/keys",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/keys",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "keys"
              ]
            },
            "description": "Signing keys for bundle manifest verification. No auth required.",
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "2 · Extract (with evidence bundle)",
      "item": [
        {
          "name": "POST /v1/extract — full bundle (sets BUNDLE_ID)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?sync=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "sync",
                  "value": "true"
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"store\": true,\n  \"include\": [\n    \"markdown\",\n    \"summary\",\n    \"screenshot\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Extract + AI analysis with full evidence bundle. Requires `\"store\": true` in the body (the default is lean/no-bundle). Returns `bundle_id`, artifacts, and provenance. Sets BUNDLE_ID for subsequent requests."
          },
          "protocolProfileBehavior": {
            "requestTimeout": 120000
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.bundle_id) {",
                  "  setFlowVar('BUNDLE_ID', data.bundle_id);",
                  "  console.log('BUNDLE_ID set to', data.bundle_id);",
                  "}",
                  "if (data.bundle_id) {",
                  "  setFlowVar('PREV_BUNDLE_ID', data.bundle_id);",
                  "  console.log('PREV_BUNDLE_ID set to', data.bundle_id);",
                  "}",
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has bundle_id', () => { pm.expect(pm.response.json().bundle_id).to.match(/^ev_/); });",
                  "pm.test('has provenance.manifest_sha256', () => {",
                  "  pm.expect(pm.response.json().provenance).to.be.an('object');",
                  "  pm.expect(pm.response.json().provenance.manifest_sha256).to.match(/^[a-f0-9]{64}$/);",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id — retrieve bundle",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const id = pm.collectionVariables.get('BUNDLE_ID') || pm.environment.get('BUNDLE_ID');",
                  "if (!id || !/^ev_/.test(id)) {",
                  "  throw new Error('BUNDLE_ID not set — run POST /v1/extract (full bundle) first.');",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function flowVar(key) {",
                  "  return pm.collectionVariables.get(key) || pm.environment.get(key);",
                  "}",
                  "",
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('id matches', () => { pm.expect(pm.response.json().bundle_id).to.eql(flowVar('BUNDLE_ID')); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/verify — integrity check",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/verify",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "verify"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('valid true', () => { pm.expect(pm.response.json().valid).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/verify?quick=true",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/verify?quick=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "verify"
              ],
              "query": [
                {
                  "key": "quick",
                  "value": "true"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/download — ZIP archive",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/download",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "download"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract/:id/verify-citation",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/verify-citation",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "verify-citation"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"chunk_id\": \"c_0\",\n  \"text\": \"A Light in the Attic\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/history — version chain",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/history",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "history"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/provenance",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/provenance",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "provenance"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract/:id/provenance",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/provenance",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "provenance"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"agent_id\": \"demo-agent\",\n  \"action\": \"qa\",\n  \"query\": \"What is the book title?\",\n  \"result_summary\": \"A Light in the Attic\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('201 created', () => { pm.response.to.have.status(201); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract/:id/handoff",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/handoff",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "handoff"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"from_agent\": \"demo-agent-a\",\n  \"to_agent\": \"demo-agent-b\",\n  \"note\": \"Passing for review\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('201 created', () => { pm.response.to.have.status(201); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/chain",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/chain",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "chain"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "PUT /v1/extract/:id/hold",
          "request": {
            "method": "PUT",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/hold",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "hold"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('legal_hold true', () => { pm.expect(pm.response.json().legal_hold).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "DELETE /v1/extract/:id/hold",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/hold",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "hold"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('legal_hold false', () => { pm.expect(pm.response.json().legal_hold).to.be.false; });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract/:id/notarize",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/notarize",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "notarize"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const skip = pm.collectionVariables.get('SKIP_NOTARIZE') || pm.environment.get('SKIP_NOTARIZE');",
                  "if (skip === 'true' || skip === true) {",
                  "  console.log('Skipping notarize (SKIP_NOTARIZE=true)');",
                  "  pm.execution.skipRequest();",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has attestation', () => { pm.expect(pm.response.json()).to.have.property('attestation'); });",
                  "if (pm.response.code !== 200) {",
                  "  const err = pm.response.json().error || pm.response.text();",
                  "  console.warn('[notarize failed]', pm.response.code, err);",
                  "  console.warn('Notarize failed — on-chain attestation may be unavailable. Set SKIP_NOTARIZE=true to skip.');",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract — throwaway bundle (for delete demo)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?sync=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "sync",
                  "value": "true"
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"mode\": \"summarize\",\n  \"store\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.bundle_id) {",
                  "  setFlowVar('DELETE_BUNDLE_ID', data.bundle_id);",
                  "  console.log('DELETE_BUNDLE_ID set to', data.bundle_id);",
                  "}",
                  "pm.test('200 ok or rate limited', () => { pm.expect([200, 429]).to.include(pm.response.code); });",
                  "if (pm.response.code === 200) {",
                  "  pm.test('has bundle_id', () => { pm.expect(pm.response.json().bundle_id).to.match(/^ev_/); });",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "DELETE /v1/extract/:id — delete bundle",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{DELETE_BUNDLE_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{DELETE_BUNDLE_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok or no bundle to delete', () => {",
                  "  pm.expect([200, 404]).to.include(pm.response.code);",
                  "});",
                  "if (pm.response.code === 200) {",
                  "  pm.test('deleted true', () => { pm.expect(pm.response.json().deleted).to.be.true; });",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "2b · Signed action receipts",
      "item": [
        {
          "name": "GET /v1/extract/:id/receipts — list action receipts",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{BUNDLE_ID}}/receipts",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{BUNDLE_ID}}",
                "receipts"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "const data = pm.response.json();",
                  "pm.test('receipts is an array', () => { pm.expect(data.receipts).to.be.an('array'); });",
                  "if (data.receipts && data.receipts.length) {",
                  "  pm.collectionVariables.set('RECEIPT_ID', data.receipts[0].id);",
                  "  console.log('RECEIPT_ID set to', data.receipts[0].id);",
                  "} else {",
                  "  console.log('No receipts yet — call get_bundle/verify_bundle/notarize_bundle/add_document_to_collection via MCP against this bundle to generate one.');",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/receipts/:id/verify — verify receipt signature",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/receipts/{{RECEIPT_ID}}/verify",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "receipts",
                "{{RECEIPT_ID}}",
                "verify"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const id = pm.collectionVariables.get('RECEIPT_ID') || pm.environment.get('RECEIPT_ID');",
                  "if (!id || !/^rcpt_/.test(id)) {",
                  "  console.log('Skipping — no RECEIPT_ID. Receipts are created by calling get_bundle / verify_bundle / notarize_bundle / add_document_to_collection via MCP, not by this REST collection.');",
                  "  pm.execution.skipRequest();",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has signature_valid + manifest_matches_current', () => {",
                  "  const j = pm.response.json();",
                  "  pm.expect(j.signature_valid).to.be.a('boolean');",
                  "  pm.expect(j.manifest_matches_current).to.be.a('boolean');",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "3 · Focused analysis (lean — no bundle)",
      "item": [
        {
          "name": "POST /v1/extract — lean (no bundle, default)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Lean extract — AI analysis with no stored bundle. This is the default behaviour (`store: false`). Response contains `result` but no `bundle_id`, artifacts, or provenance."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('store false', () => { pm.expect(pm.response.json().store).to.be.false; });",
                  "pm.test('no bundle_id', () => { pm.expect(pm.response.json().bundle_id).to.be.undefined; });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract?max_age=300 — cached browser fetch",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?max_age=300",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "max_age",
                  "value": "300"
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"mode\": \"summarize\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Browser content cache: if the same URL was fetched within `max_age` seconds, the raw page content is served from KV cache (browser launch + OCR skipped). AI analysis always runs fresh. Run this request twice — the second call should be noticeably faster."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('store false', () => { pm.expect(pm.response.json().store).to.be.false; });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract — PDF upload (lean, no bundle)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?store=false",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "store",
                  "value": "false"
                }
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file"
                },
                {
                  "key": "mode",
                  "type": "text",
                  "value": "invoice"
                }
              ]
            },
            "description": "Multipart PDF upload (lean, no bundle). In Postman Body → form-data, select a PDF file for the `file` field."
          },
          "protocolProfileBehavior": {
            "requestTimeout": 120000
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/summarize",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/summarize",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "summarize"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/qa",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/qa",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "qa"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"question\": \"What is the price of the book?\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/translate",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/translate",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "translate"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"target_lang\": \"es\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/check-claims",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/check-claims",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "check-claims"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"claims\": [\n    \"The book is titled A Light in the Attic\",\n    \"The book is in stock\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/describe",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/describe",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "describe"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "3b · Invoice (evidence bundle)",
      "item": [
        {
          "name": "POST /v1/extract — invoice URL → evidence bundle",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?sync=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "sync",
                  "value": "true"
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"https://www.w3.org/WAI/WCAG21/Techniques/pdf/sample.pdf\",\n  \"mode\": \"invoice\",\n  \"store\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "protocolProfileBehavior": {
            "requestTimeout": 120000
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.bundle_id) {",
                  "  setFlowVar('INVOICE_BUNDLE_ID', data.bundle_id);",
                  "  console.log('INVOICE_BUNDLE_ID set to', data.bundle_id);",
                  "}",
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has bundle_id', () => { pm.expect(pm.response.json().bundle_id).to.match(/^ev_/); });",
                  "pm.test('has invoice result', () => {",
                  "  const r = pm.response.json().result;",
                  "  pm.expect(r.invoice || r.invoice_cited).to.exist;",
                  "});",
                  "pm.test('has provenance', () => { pm.expect(pm.response.json().provenance).to.be.an('object'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id — invoice bundle",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{INVOICE_BUNDLE_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{INVOICE_BUNDLE_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('mode is invoice', () => { pm.expect(pm.response.json().mode).to.eql('invoice'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/extract/:id/verify — invoice bundle",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract/{{INVOICE_BUNDLE_ID}}/verify",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract",
                "{{INVOICE_BUNDLE_ID}}",
                "verify"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('valid true', () => { pm.expect(pm.response.json().valid).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/extract — invoice PDF upload → evidence bundle",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?sync=true&store=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "sync",
                  "value": "true"
                },
                {
                  "key": "store",
                  "value": "true"
                }
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file"
                },
                {
                  "key": "mode",
                  "type": "text",
                  "value": "invoice"
                }
              ]
            },
            "description": "Multipart PDF upload with full evidence bundle. In Postman Body → form-data, select a PDF file for the `file` field."
          },
          "protocolProfileBehavior": {
            "requestTimeout": 120000
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has bundle_id', () => { pm.expect(pm.response.json().bundle_id).to.match(/^ev_/); });",
                  "pm.test('has invoice result', () => {",
                  "  const r = pm.response.json().result;",
                  "  pm.expect(r.invoice || r.invoice_cited).to.exist;",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "4 · Async jobs",
      "item": [
        {
          "name": "POST /v1/extract?async=true — queue job",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?async=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "async",
                  "value": "true"
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"mode\": \"summarize\",\n  \"store\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "protocolProfileBehavior": {
            "requestTimeout": 120000
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.job_id) {",
                  "  setFlowVar('JOB_ID', data.job_id);",
                  "  console.log('JOB_ID set to', data.job_id);",
                  "}",
                  "pm.test('202 queued', () => { pm.response.to.have.status(202); });",
                  "pm.test('has job_id', () => { pm.expect(pm.response.json().job_id).to.match(/^job_/); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/jobs/:id — job status",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/jobs/{{JOB_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "jobs",
                "{{JOB_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function flowVar(key) {",
                  "  return pm.collectionVariables.get(key) || pm.environment.get(key)",
                  "}",
                  "",
                  "const jobId = flowVar('JOB_ID')",
                  "const baseUrl = pm.variables.replaceIn('{{BASE_URL}}')",
                  "const apiKey = pm.collectionVariables.get('API_KEY') || pm.environment.get('API_KEY')",
                  "",
                  "const maxAttempts = 30",
                  "const delayMs = 2000",
                  "let attempt = 0",
                  "",
                  "function poll() {",
                  "  attempt += 1",
                  "  pm.sendRequest(",
                  "    {",
                  "      url: `${baseUrl}/v1/jobs/${jobId}`,",
                  "      method: 'GET',",
                  "      header: { Authorization: `Bearer ${apiKey}` },",
                  "    },",
                  "    (err, res) => {",
                  "      pm.test('200 ok', () => {",
                  "        if (err) throw err",
                  "        pm.expect(res.code).to.eql(200)",
                  "      })",
                  "",
                  "      const body = res.json()",
                  "      const status = body.status",
                  "",
                  "      if (status === 'complete') {",
                  "        pm.test('job reached complete', () => {",
                  "          pm.expect(status).to.eql('complete')",
                  "        })",
                  "        return",
                  "      }",
                  "",
                  "      if (status === 'failed') {",
                  "        pm.test('job reached complete', () => {",
                  "          throw new Error(`Job failed: ${body.error || JSON.stringify(body)}`)",
                  "        })",
                  "        return",
                  "      }",
                  "",
                  "      if (attempt >= maxAttempts) {",
                  "        pm.test('job reached complete', () => {",
                  "          throw new Error(`Job still ${status} after ${maxAttempts} attempts (${maxAttempts * delayMs / 1000}s)`)",
                  "        })",
                  "        return",
                  "      }",
                  "",
                  "      setTimeout(poll, delayMs)",
                  "    },",
                  "  )",
                  "}",
                  "",
                  "pm.test('JOB_ID is set', () => {",
                  "  pm.expect(jobId, 'Run async job step first').to.match(/^job_/)",
                  "})",
                  "",
                  "poll()"
                ]
              }
            }
          ]
        },
        {
          "name": "job · async=true lean (store=false returns 200 synchronously)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/extract?async=true",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "extract"
              ],
              "query": [
                {
                  "key": "async",
                  "value": "true"
                }
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"source\": \"{{TARGET_URL}}\",\n  \"mode\": \"summarize\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 sync (async ignored for lean)', () => { pm.response.to.have.status(200); });",
                  "pm.test('store false', () => { pm.expect(pm.response.json().store).to.be.false; });",
                  "pm.test('no job_id (lean is always sync)', () => { pm.expect(pm.response.json().job_id).to.be.undefined; });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/jobs — batch queue",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/jobs",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "jobs"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"items\": [\n    {\n      \"source\": \"{{TARGET_URL}}\"\n    },\n    {\n      \"source\": \"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html\"\n    }\n  ],\n  \"mode\": \"summarize\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('202 queued', () => { pm.response.to.have.status(202); });",
                  "pm.test('has job_id', () => { pm.expect(pm.response.json().job_id).to.match(/^job_/); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "5 · Collections & search",
      "item": [
        {
          "name": "POST /v1/collections — create (sets COLLECTION_ID)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Demo Matter\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.collection_id) {",
                  "  setFlowVar('COLLECTION_ID', data.collection_id);",
                  "  console.log('COLLECTION_ID set to', data.collection_id);",
                  "}",
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/collections",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/collections/:id",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/collections/:id/documents — add bundle",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}/documents",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}",
                "documents"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"bundle_id\": \"{{BUNDLE_ID}}\",\n  \"async\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.job_id) {",
                  "  setFlowVar('JOB_ID', data.job_id);",
                  "  console.log('JOB_ID set to', data.job_id);",
                  "}",
                  "pm.test('202 queued', () => { pm.response.to.have.status(202); });",
                  "pm.test('has job_id', () => { pm.expect(pm.response.json().job_id).to.match(/^job_/); });"
                ]
              }
            }
          ]
        },
        {
          "name": "error · duplicate document (409)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}/documents",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}",
                "documents"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"bundle_id\": \"{{BUNDLE_ID}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('409 duplicate', () => { pm.response.to.have.status(409); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/jobs/:id — index job status",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/jobs/{{JOB_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "jobs",
                "{{JOB_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function flowVar(key) {",
                  "  return pm.collectionVariables.get(key) || pm.environment.get(key)",
                  "}",
                  "",
                  "const jobId = flowVar('JOB_ID')",
                  "const baseUrl = pm.variables.replaceIn('{{BASE_URL}}')",
                  "const apiKey = pm.collectionVariables.get('API_KEY') || pm.environment.get('API_KEY')",
                  "",
                  "const maxAttempts = 30",
                  "const delayMs = 2000",
                  "let attempt = 0",
                  "",
                  "function poll() {",
                  "  attempt += 1",
                  "  pm.sendRequest(",
                  "    {",
                  "      url: `${baseUrl}/v1/jobs/${jobId}`,",
                  "      method: 'GET',",
                  "      header: { Authorization: `Bearer ${apiKey}` },",
                  "    },",
                  "    (err, res) => {",
                  "      pm.test('200 ok', () => {",
                  "        if (err) throw err",
                  "        pm.expect(res.code).to.eql(200)",
                  "      })",
                  "",
                  "      const body = res.json()",
                  "      const status = body.status",
                  "",
                  "      if (status === 'complete') {",
                  "        pm.test('job reached complete', () => {",
                  "          pm.expect(status).to.eql('complete')",
                  "        })",
                  "        return",
                  "      }",
                  "",
                  "      if (status === 'failed') {",
                  "        pm.test('job reached complete', () => {",
                  "          throw new Error(`Job failed: ${body.error || JSON.stringify(body)}`)",
                  "        })",
                  "        return",
                  "      }",
                  "",
                  "      if (attempt >= maxAttempts) {",
                  "        pm.test('job reached complete', () => {",
                  "          throw new Error(`Job still ${status} after ${maxAttempts} attempts (${maxAttempts * delayMs / 1000}s)`)",
                  "        })",
                  "        return",
                  "      }",
                  "",
                  "      setTimeout(poll, delayMs)",
                  "    },",
                  "  )",
                  "}",
                  "",
                  "pm.test('JOB_ID is set', () => {",
                  "  pm.expect(jobId, 'Run async job step first').to.match(/^job_/)",
                  "})",
                  "",
                  "poll()"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/collections/:id/search — semantic search",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}/search?q=light in attic&limit=5",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}",
                "search"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "light in attic"
                },
                {
                  "key": "limit",
                  "value": "5"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok or vectorize unavailable', () => {",
                  "  pm.expect([200, 503]).to.include(pm.response.code);",
                  "});",
                  "if (pm.response.code === 200) {",
                  "  pm.test('has results array', () => { pm.expect(pm.response.json().results).to.be.an('array'); });",
                  "  pm.test('search returned hits', () => {",
                  "    const n = pm.response.json().results.length;",
                  "    if (n === 0) console.warn('Search returned 0 hits — index may still be warming');",
                  "    pm.expect(n, 'Index may still be running').to.be.at.least(0);",
                  "  });",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/collections/:id/ask — cross-document Q&A",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}/ask",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}",
                "ask"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"question\": \"Which books are in stock and what are their prices?\",\n  \"max_chunks\": 8\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok or vectorize unavailable', () => {",
                  "  pm.expect([200, 503]).to.include(pm.response.code);",
                  "});",
                  "if (pm.response.code === 503) {",
                  "  console.warn('ask 503 — semantic search unavailable on this account or plan');",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/collections/:id/documents/:bundleId/reindex",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}/documents/{{BUNDLE_ID}}/reindex",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}",
                "documents",
                "{{BUNDLE_ID}}",
                "reindex"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('202 queued or already indexed', () => {",
                  "  pm.expect(pm.response.code).to.be.oneOf([202, 409]);",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "DELETE /v1/collections/:id/documents/:bundleId",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{BASE_URL}}/v1/collections/{{COLLECTION_ID}}/documents/{{BUNDLE_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "collections",
                "{{COLLECTION_ID}}",
                "documents",
                "{{BUNDLE_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "6 · Monitor",
      "item": [
        {
          "name": "POST /v1/monitor — create (sets MONITOR_ID)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"{{TARGET_URL}}\",\n  \"mode\": \"diff\",\n  \"webhook_url\": \"{{WEBHOOK_URL}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.id) {",
                  "  setFlowVar('MONITOR_ID', data.id);",
                  "  console.log('MONITOR_ID set to', data.id);",
                  "}",
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });"
                ]
              }
            }
          ]
        },
        {
          "name": "monitor · mode=always (sets MONITOR_ALWAYS_ID)",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"{{TARGET_URL}}\",\n  \"mode\": \"always\",\n  \"webhook_url\": \"{{WEBHOOK_URL}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "function setFlowVar(key, value) {",
                  "  pm.collectionVariables.set(key, value)",
                  "  pm.environment.set(key, value)",
                  "}",
                  "",
                  "const data = pm.response.json();",
                  "if (data.id) {",
                  "  setFlowVar('MONITOR_ALWAYS_ID', data.id);",
                  "  console.log('MONITOR_ALWAYS_ID set to', data.id);",
                  "}",
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });",
                  "pm.test('mode is always', () => { pm.expect(pm.response.json().mode).to.eql('always'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/monitor — list monitors",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/monitor/:id — monitor details",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor/{{MONITOR_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor",
                "{{MONITOR_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "GET /v1/monitor/:id/history — change history",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor/{{MONITOR_ID}}/history?limit=50&offset=0",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor",
                "{{MONITOR_ID}}",
                "history"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "offset",
                  "value": "0"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });"
                ]
              }
            }
          ]
        },
        {
          "name": "DELETE /v1/monitor/:id — delete monitor",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor/{{MONITOR_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor",
                "{{MONITOR_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });"
                ]
              }
            }
          ]
        },
        {
          "name": "DELETE /v1/monitor/:id (always)",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{BASE_URL}}/v1/monitor/{{MONITOR_ALWAYS_ID}}",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "monitor",
                "{{MONITOR_ALWAYS_ID}}"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('2xx ok', () => { pm.expect(pm.response.code).to.be.within(200, 299); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "7 · Quota & feedback",
      "item": [
        {
          "name": "GET /v1/quota — credits & usage",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{BASE_URL}}/v1/quota",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "quota"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('has remaining credits', () => {",
                  "  const j = pm.response.json();",
                  "  pm.expect(j.remaining).to.be.a('number');",
                  "  pm.expect(j.monthly_credits).to.be.a('number');",
                  "  pm.expect(j.plan_id).to.exist;",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "POST /v1/feedback — send feedback",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{BASE_URL}}/v1/feedback",
              "host": [
                "{{BASE_URL}}"
              ],
              "path": [
                "v1",
                "feedback"
              ]
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"rating\": \"good\",\n  \"message\": \"API works as expected\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200 ok', () => { pm.response.to.have.status(200); });",
                  "pm.test('received true', () => { pm.expect(pm.response.json().received).to.be.true; });"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
