{
  "info": {
    "name": "Bulk URL Checker API",
    "description": "Public REST API for https://bulkurlchecker.com\n\nQuickstart:\n1. Create an API key at https://app.bulkurlchecker.com/dashboard/api-keys\n2. Open this collection's **Variables** tab and paste it into `api_key`.\n3. Run **Submit job** -- the response's `job_id` is captured into the `job_id` variable automatically by the test script, so the follow-up requests work without copy/paste.\n\nFull spec: https://api.bulkurlchecker.com/openapi.json\nSDKs:  https://pypi.org/project/bulkurlchecker/  |  https://www.npmjs.com/package/bulkurlchecker",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_postman_id": "f0c2c1a4-bulk-url-checker-v2"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      { "key": "token", "value": "{{api_key}}", "type": "string" }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.bulkurlchecker.com",
      "type": "string",
      "description": "Public API root. No need to change."
    },
    {
      "key": "api_key",
      "value": "uck_live_YOUR_KEY_HERE",
      "type": "string",
      "description": "Your secret API key. Get one at https://app.bulkurlchecker.com/dashboard/api-keys"
    },
    {
      "key": "job_id",
      "value": "",
      "type": "string",
      "description": "Populated automatically by the 'Submit job' request's test script."
    }
  ],
  "item": [
    {
      "name": "Jobs",
      "item": [
        {
          "name": "Submit job",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Capture job_id into a collection variable so the follow-up",
                  "// requests in this collection can reference it without copy/paste.",
                  "pm.test('returns 200 with job_id', function () {",
                  "    pm.response.to.have.status(200);",
                  "    const body = pm.response.json();",
                  "    pm.expect(body.job_id, 'body.job_id').to.be.a('string').and.not.empty;",
                  "    pm.collectionVariables.set('job_id', body.job_id);",
                  "    console.log('Captured job_id:', body.job_id);",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"urls\": [\n    \"https://example.com\",\n    \"https://example.org\"\n  ]\n}"
            },
            "url": {
              "raw": "{{base_url}}/api/v2/jobs",
              "host": ["{{base_url}}"],
              "path": ["api", "v2", "jobs"]
            },
            "description": "Submit a batch of URLs. Returns a `job_id` and the engine starts checking immediately.\n\nFor large batches (> ~2,000 URLs) use this endpoint -- it returns instantly. For small batches where you want results in one shot, use **Submit and wait** instead.\n\nResponse:\n```\n{\n  \"job_id\": \"a1b2c3...\",\n  \"status\": \"pending\",\n  \"total_urls\": 2,\n  \"completed_urls\": 0\n}\n```"
          }
        },
        {
          "name": "Submit and wait (returns full results)",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"urls\": [\n    \"https://example.com\",\n    \"https://example.org\"\n  ]\n}"
            },
            "url": {
              "raw": "{{base_url}}/api/v2/jobs/wait?wait_seconds=60&poll_interval=2",
              "host": ["{{base_url}}"],
              "path": ["api", "v2", "jobs", "wait"],
              "query": [
                { "key": "wait_seconds", "value": "60", "description": "Max seconds the server will wait for completion before returning what's done (1-900)." },
                { "key": "poll_interval", "value": "2", "description": "Poll interval inside the server-side wait, seconds." }
              ]
            },
            "description": "Synchronous wrapper: submits URLs and blocks on the server side until results are ready (or `wait_seconds` elapses). Use for small batches and shell pipelines. For >2,000 URLs use **Submit job** then page through **Get results**."
          }
        },
        {
          "name": "Get job status",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/api/v2/jobs/{{job_id}}",
              "host": ["{{base_url}}"],
              "path": ["api", "v2", "jobs", "{{job_id}}"]
            },
            "description": "Status + progress for a previously-submitted job.\n\n`status` will be one of: `pending`, `running`, `completed`, `paused`, `failed`, `cancelled`."
          }
        },
        {
          "name": "Get results (paginated)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/api/v2/jobs/{{job_id}}/results?limit=1000&offset=0",
              "host": ["{{base_url}}"],
              "path": ["api", "v2", "jobs", "{{job_id}}", "results"],
              "query": [
                { "key": "limit", "value": "1000", "description": "Page size, up to 1000." },
                { "key": "offset", "value": "0", "description": "Page offset." }
              ]
            },
            "description": "Paginated results for a job. Each item carries `url`, `status_code`, `final_url`, `redirect_chain`, `is_broken`, `is_soft_404`, `response_time_ms`. Iterate with `offset` += `limit` until you get a short or empty page."
          }
        },
        {
          "name": "Cancel job (refunds unchecked credits)",
          "request": {
            "method": "DELETE",
            "url": {
              "raw": "{{base_url}}/api/v2/jobs/{{job_id}}",
              "host": ["{{base_url}}"],
              "path": ["api", "v2", "jobs", "{{job_id}}"]
            },
            "description": "Cancel a job mid-run. Any URLs not yet checked are refunded to your credit balance."
          }
        }
      ]
    },
    {
      "name": "Account",
      "item": [
        {
          "name": "Get usage / credit balance",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{base_url}}/api/v2/usage",
              "host": ["{{base_url}}"],
              "path": ["api", "v2", "usage"]
            },
            "description": "Current month usage and credit balance for the key holder."
          }
        }
      ]
    }
  ]
}
