{
  "auth": {
    "bearer": [
      {
        "key": "token",
        "type": "string",
        "value": "{{IRONFANG_API_KEY}}"
      }
    ],
    "type": "bearer"
  },
  "info": {
    "description": "Asynchronous website audits with signed, independently timestamped evidence.\nSites, rules and rule packs, audits, findings, evidence bundles, exports,\nwebhooks and usage - authenticated with an Ironfang platform API key\ncarrying Ironfang Audit scopes. Base URL https://api.ironfang.com/audit.\n\nFor agents and tools: the canonical base URL is\nhttps://api.ironfang.com/audit and every operation has a stable\n`operationId`. Every error an operation returns is JSON of the shape\n`{\"error\": {\"code\", \"message\", \"docs\"}, \"request_id\"}`: branch on `code`\nand the HTTP status, never on `message`. The machine-readable index of the\nIronfang APIs is https://ironfang.com/.well-known/api-catalog, and\nhttps://ironfang.com/llms.txt is a plain-text map of them for a language\nmodel. Ironfang Audit is also available as MCP tools at\nhttps://mcp.ironfang.com/mcp (see https://ironfang.com/docs/mcp). Auditwolf\nis the name the product launched under, not a separate product; its\n`/auditwolf` prefix and `Auditwolf-*` webhook headers were retired on\n28 September 2026, and the prefix now answers `410`.\n\nBilling: Ironfang Audit has no plans of its own. It is billed through the\norganisation's Ironfang billing account (https://api.ironfang.com/billing/v1)\non two meters: `audit.capture`, one finalised page evidence record, and\n`audit.retention_extension`, extended hosted retention bought as a quoted,\nfixed-price operation. Every audit is admitted before it is accepted: the\nmost pages it can capture are reserved against `audit.capture`, a refusal\nis answered at once with one of the shared billing codes (see the Problem\nresponse), and a finished audit is charged only for the page evidence it\nfinalised. Capacity limits - sites per organisation, pages per audit,\ncrawl rate and depth - are the same for everyone and no payment lifts\nthem. The retired `/v1/plans` and `/v1/billing` routes answer `410\nbilling_moved`.\n\nGenerated from info.version 1.0.0. Start with the Getting started folder: the first request needs no credential and the rest need a free account. Set IRONFANG_API_KEY in a private Postman environment or vault reference; no credential is included in this collection. The starter requests store the site and audit ids they create in collection variables so the later requests can use them. Do not export credentials.",
    "name": "Ironfang Audit API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "description": "Run these in order. The first needs no credential. The rest need an API key from https://portal.ironfang.com with Ironfang Audit scopes, in a private environment as IRONFANG_API_KEY. Requests 2 and 3 store the ids they create in the siteId and auditId collection variables.",
      "item": [
        {
          "name": "1. See the signing keys",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "description": "The public keys Ironfang Audit signs evidence manifests with, for verifying a bundle offline. Needs no credential, so send it first to prove the base URL and network path.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "verify",
                "v1",
                "signing-keys"
              ],
              "query": [],
              "raw": "{{base_url}}/verify/v1/signing-keys"
            }
          },
          "response": []
        },
        {
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "const body = pm.response.json();",
                  "if (body \u0026\u0026 body.id) {",
                  "    pm.collectionVariables.set(\"siteId\", body.id);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "name": "2. Create a site",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"name\": \"Ironfang\",\n  \"timezone\": \"Europe/London\",\n  \"url\": \"https://ironfang.com\"\n}"
            },
            "description": "Registers a site to audit. Change `url` to a site you are entitled to audit. The response id is stored in the siteId collection variable for the next request.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites"
            }
          },
          "response": []
        },
        {
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "const body = pm.response.json();",
                  "if (body \u0026\u0026 body.id) {",
                  "    pm.collectionVariables.set(\"auditId\", body.id);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "name": "3. Trigger an audit",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"reason\": \"First audit from Postman\",\n  \"trigger_type\": \"api\"\n}"
            },
            "description": "Queues an asynchronous audit of the site created in the previous request. Returns 202 with the audit; its id is stored in the auditId collection variable.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "audits"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/audits"
            }
          },
          "response": []
        },
        {
          "name": "4. Poll the audit",
          "request": {
            "description": "The audit's lifecycle, compliance and integrity state. Send it again until the status is terminal, then list its findings and download the evidence bundle from the Audits folder.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "audits",
                "{{auditId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/audits/{{auditId}}"
            }
          },
          "response": []
        }
      ],
      "name": "Getting started"
    },
    {
      "description": "Sites under audit.",
      "item": [
        {
          "name": "List sites",
          "request": {
            "description": "Returns the sites owned by the authenticated organisation, including their stored audit configuration and complete per-site activity facts. Counts and last audit come from authoritative tenant-scoped queries, independently of history page limits.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites"
            }
          },
          "response": []
        },
        {
          "name": "Create a site",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"crawl_policy\": {},\n  \"name\": \"\",\n  \"timezone\": \"UTC\",\n  \"url\": \"https://example.com\"\n}"
            },
            "description": "Registers a public website for the authenticated organisation. The URL must pass the public-target policy and the organisation must be below the site capacity limit (250 sites unless the deployment sets otherwise, for every organisation whatever it pays). A crawl policy is held inside the crawl ceilings and the per-audit page cap. robots.txt is respected unless the policy explicitly sets `respect_robots` to false.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites"
            }
          },
          "response": []
        },
        {
          "name": "Get a site",
          "request": {
            "description": "Returns stored site configuration and complete activity facts. A site outside the authenticated organisation is reported as not found.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}"
            }
          },
          "response": []
        },
        {
          "name": "List site audits",
          "request": {
            "description": "Returns audit runs for the selected site within the authenticated organisation. A site outside the organisation is reported as not found.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "audits"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "status",
                  "value": "{{status}}"
                }
              ],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/audits"
            }
          },
          "response": []
        },
        {
          "name": "Trigger an asynchronous audit",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"reason\": \"\",\n  \"single_page\": false,\n  \"trigger_type\": \"api\"\n}"
            },
            "description": "Admits and queues an audit for the organisation's site and returns its initial lifecycle state. Admission comes first: the most pages the audit can capture (`page_bound`: the site's page limit within the per-audit cap, or one page for single_page) are reserved against the `audit.capture` meter of the organisation's billing account. A refusal is answered now with the shared billing code and no audit exists. The audit then captures at most `page_bound` pages and is charged only for the page evidence it finalises. Reusing an Idempotency-Key returns the existing audit and reserves nothing more; single_page limits the scope to the site's primary URL.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "disabled": true,
                "key": "Idempotency-Key",
                "value": "{{Idempotency-Key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "audits"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/audits"
            }
          },
          "response": []
        },
        {
          "name": "List the site's monitors",
          "request": {
            "description": "Returns the organisation's non-archived monitors for the selected site, including their scheduling configuration.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "monitors"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/monitors"
            }
          },
          "response": []
        },
        {
          "name": "Create a monitor",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"anchor_minute\": 0,\n  \"cadence\": \"manual\",\n  \"capture_profile\": {},\n  \"change_policy\": {},\n  \"mode\": \"full_site\",\n  \"name\": \"\",\n  \"timezone\": \"\",\n  \"urls\": []\n}"
            },
            "description": "`mode` is `full_site` (crawler discovery under the site's crawl policy) or `url_set` (exactly the given `urls`, validated against the site's hosts, patterns and the public-target policy; the whole set is refused if any entry fails). `cadence` is `manual`, `daily`, `six_hourly` or `hourly`, open to every organisation; each scheduled run is admitted against `audit.capture` when its slot arrives, and a refused run is skipped with a `monitor.skipped` event whose `reason` is the billing code. `anchor_minute` is minutes past midnight in `timezone` for daily, or within the interval otherwise.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "monitors"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/monitors"
            }
          },
          "response": []
        },
        {
          "name": "Packs installed on this site",
          "request": {
            "description": "Includes latest_version and upgrade_available. A newer pack is never applied on its own; you are told one exists.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "rule-packs"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/rule-packs"
            }
          },
          "response": []
        },
        {
          "name": "Install a rule pack",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"pack_key\": \"\",\n  \"variables\": {}\n}"
            },
            "description": "Installs the selected catalogue pack on the organisation's site using the supplied variable values. The pack's templates become site rules with their own revision history.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "rule-packs"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/rule-packs"
            }
          },
          "response": []
        },
        {
          "name": "List the site's versioned deterministic rules",
          "request": {
            "description": "Returns the deterministic rules configured for a site owned by the authenticated organisation, with their version and configuration metadata.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "rules"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/rules"
            }
          },
          "response": []
        },
        {
          "name": "Create a deterministic rule",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"configuration\": {},\n  \"name\": \"\",\n  \"rule_type\": \"\",\n  \"severity\": \"info\"\n}"
            },
            "description": "Validates the rule type and configuration, then creates a versioned rule for the selected site. Invalid configurations are rejected before an audit can run them.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "sites",
                "{{siteId}}",
                "rules"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/sites/{{siteId}}/rules"
            }
          },
          "response": []
        }
      ],
      "name": "Sites"
    },
    {
      "description": "Audit runs, their pages and evidence.",
      "item": [
        {
          "name": "List organisation audits",
          "request": {
            "description": "Returns audit runs across the sites owned by the authenticated organisation, including each run's current lifecycle state.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "audits"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "status",
                  "value": "{{status}}"
                },
                {
                  "disabled": true,
                  "key": "site_id",
                  "value": "{{site_id}}"
                }
              ],
              "raw": "{{base_url}}/v1/audits"
            }
          },
          "response": []
        },
        {
          "name": "Get audit lifecycle, compliance and integrity state",
          "request": {
            "description": "Returns the organisation's audit record, including its processing status and recorded compliance and evidence-integrity results. Processing completion is distinct from passing the audit rules.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "audits",
                "{{auditId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/audits/{{auditId}}"
            }
          },
          "response": []
        },
        {
          "name": "Download the independently verifiable evidence ZIP",
          "request": {
            "description": "Downloads the evidence bundle after the audit reaches completed or partial status. A bundle whose hosted artifacts have expired returns evidence_expired; retained hashes and signing metadata do not restore those files.",
            "header": [
              {
                "key": "Accept",
                "value": "application/zip"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "audits",
                "{{auditId}}",
                "evidence"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/audits/{{auditId}}/evidence"
            }
          },
          "response": []
        },
        {
          "name": "Queue a manual S3 export",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"destination_id\": \"00000000-0000-0000-0000-000000000000\"\n}"
            },
            "description": "Queues delivery of a completed audit's evidence bundle to an S3 destination owned by the same organisation. The response acknowledges the export job; delivery progress is available from the exports endpoint.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "audits",
                "{{auditId}}",
                "exports"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/audits/{{auditId}}/exports"
            }
          },
          "response": []
        },
        {
          "name": "Page observations of an audit",
          "request": {
            "description": "Supply limit or cursor to opt into bounded pages ordered by immutable created_at then ID descending. Filter-only and queryless requests retain the legacy complete response. Filters are case-insensitive comma lists. change accepts new, changed, moved and unchanged; compliance accepts pass, warning, fail, error and none (no recorded state); capture accepts captured and error (failed is an alias). q is a literal substring of requested URL, final URL or title. total is always the unfiltered audit count. Paged lists include rule results but omit artifacts; use the observation detail endpoint for retained artifact metadata.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "audits",
                "{{auditId}}",
                "pages"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "change",
                  "value": "{{change}}"
                },
                {
                  "disabled": true,
                  "key": "compliance",
                  "value": "{{compliance}}"
                },
                {
                  "disabled": true,
                  "key": "capture",
                  "value": "{{capture}}"
                },
                {
                  "disabled": true,
                  "key": "q",
                  "value": "{{q}}"
                },
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                }
              ],
              "raw": "{{base_url}}/v1/audits/{{auditId}}/pages"
            }
          },
          "response": []
        }
      ],
      "name": "Audits"
    },
    {
      "description": "Findings raised by audits.",
      "item": [
        {
          "name": "The finding inbox",
          "request": {
            "description": "Outstanding problems rather than audit results. A finding is one problem on one logical page against one requirement, for as long as that pairing exists: a page that fails the same rule every night is one finding, not one per night. Defaults to everything not resolved. Use sort=created for bounded cursor pages, newest creation time then ID descending. Creation time is immutable when a later audit sees the same problem, so updates do not move findings across the cursor. Filters are evaluated on each request; pages are not a frozen snapshot of membership. Omit sort for the legacy last-seen descending, ID ascending offset list. Summary counts are separate from the number of loaded findings.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "findings"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "site_id",
                  "value": "{{site_id}}"
                },
                {
                  "disabled": true,
                  "key": "page_id",
                  "value": "{{page_id}}"
                },
                {
                  "disabled": true,
                  "key": "rule_id",
                  "value": "{{rule_id}}"
                },
                {
                  "disabled": true,
                  "key": "state",
                  "value": "{{state}}"
                },
                {
                  "disabled": true,
                  "key": "severity",
                  "value": "{{severity}}"
                },
                {
                  "disabled": true,
                  "key": "assignee",
                  "value": "{{assignee}}"
                },
                {
                  "disabled": true,
                  "key": "open_longer_than_days",
                  "value": "{{open_longer_than_days}}"
                },
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "sort",
                  "value": "{{sort}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "offset",
                  "value": "{{offset}}"
                }
              ],
              "raw": "{{base_url}}/v1/findings"
            }
          },
          "response": []
        },
        {
          "name": "Apply one decision to several findings",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"assignee_user_id\": \"\",\n  \"comment\": \"\",\n  \"ids\": [],\n  \"resolution_code\": \"false_positive\",\n  \"state\": \"acknowledged\"\n}"
            },
            "description": "The same path as a single update, once per finding, so each one gets its own event and nothing is attributed differently for having been done in a batch. Per-finding failures are reported rather than failing the request: a selection that includes one finding somebody else just resolved should still assign the other nine.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "findings",
                "bulk"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/findings/bulk"
            }
          },
          "response": []
        },
        {
          "name": "The numbers at the top of the finding inbox",
          "request": {
            "description": "Open, acknowledged and accepted counts, how many are regressions, how many are past a due date somebody set, and the median time to resolution. The median is null until something has been resolved, because a median of nothing is not zero.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "findings",
                "summary"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/findings/summary"
            }
          },
          "response": []
        },
        {
          "name": "Get one finding",
          "request": {
            "description": "Returns a finding belonging to the authenticated organisation, including its current triage state. Use the finding events endpoint to retrieve its change history.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "findings",
                "{{findingId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/findings/{{findingId}}"
            }
          },
          "response": []
        },
        {
          "name": "Assign, schedule, acknowledge, accept the risk, or close a finding",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"accepted_risk_until\": \"\",\n  \"assignee_user_id\": \"\",\n  \"comment\": \"\",\n  \"due_at\": \"\",\n  \"resolution_code\": \"false_positive\",\n  \"state\": \"acknowledged\"\n}"
            },
            "description": "A person cannot mark a finding fixed: that is a claim about the page which only a passing observation can make, so closing one by hand needs a resolution such as false_positive or accepted_risk. Reopening is likewise something an observation does. Every change is recorded against the person who made it.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "PATCH",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "findings",
                "{{findingId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/findings/{{findingId}}"
            }
          },
          "response": []
        },
        {
          "name": "The append-only history of a finding",
          "request": {
            "description": "Every state change, assignment and comment, newest first, each attributed to the person or to the system. Comments are operational records and are not part of signed evidence. A finding whose rule flaps accumulates history without anyone acting, so this is paged like the other histories.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "findings",
                "{{findingId}}",
                "events"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                }
              ],
              "raw": "{{base_url}}/v1/findings/{{findingId}}/events"
            }
          },
          "response": []
        }
      ],
      "name": "Findings"
    },
    {
      "description": "Rules and their revisions.",
      "item": [
        {
          "name": "Get the active revision of a rule",
          "request": {
            "description": "Resolves a rule's stable lineage identifier to its current revision within the authenticated organisation.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rules",
                "{{lineageId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rules/{{lineageId}}"
            }
          },
          "response": []
        },
        {
          "name": "Revise a rule",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"configuration\": {},\n  \"description\": \"\",\n  \"name\": \"\",\n  \"rule_type\": \"\",\n  \"severity\": \"info\"\n}"
            },
            "description": "Writes the next version of the rule and makes it active. Nothing about the previous revision changes, so evidence captured before the edit still names the wording that produced it. Omitted fields carry forward from the active revision.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "PATCH",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rules",
                "{{lineageId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rules/{{lineageId}}"
            }
          },
          "response": []
        },
        {
          "name": "Retire a rule",
          "request": {
            "description": "Stops the rule being evaluated in future audits. Revisions are kept, so every historical result still resolves to the exact rule that ran. Retirement is permanent; stating the requirement again creates a new rule with its own history.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "DELETE",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rules",
                "{{lineageId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rules/{{lineageId}}"
            }
          },
          "response": []
        },
        {
          "name": "Disable a rule for future audits",
          "request": {
            "description": "Affects future audits only. A historical result keeps the status it had: a rule that was failing in March was still failing in March.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rules",
                "{{lineageId}}",
                "disable"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rules/{{lineageId}}/disable"
            }
          },
          "response": []
        },
        {
          "name": "Enable a rule for future audits",
          "request": {
            "description": "Enables the organisation's rule for evaluation by future audits. Previously recorded audit results are unchanged.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rules",
                "{{lineageId}}",
                "enable"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rules/{{lineageId}}/enable"
            }
          },
          "response": []
        },
        {
          "name": "List every revision of a rule, newest first",
          "request": {
            "description": "Returns the revision history for the organisation's rule in descending version order, preserving access to the configurations referenced by earlier audit results.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rules",
                "{{lineageId}}",
                "revisions"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                }
              ],
              "raw": "{{base_url}}/v1/rules/{{lineageId}}/revisions"
            }
          },
          "response": []
        }
      ],
      "name": "Rules"
    },
    {
      "description": "Installable rule packs.",
      "item": [
        {
          "name": "The rule pack catalogue",
          "request": {
            "description": "Ironfang-maintained rule templates. A pack is a starting point, not a compliance product: each one states what it checks and, in the same breath, what it cannot tell you. Installing a pack copies rules into your own site, which you then own and can edit.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rule-packs"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rule-packs"
            }
          },
          "response": []
        },
        {
          "name": "Uninstall a pack",
          "request": {
            "description": "Retires the rules it created. They stop being evaluated; they are not deleted, so every result that referenced one still resolves.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "DELETE",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rule-packs",
                "installed",
                "{{installationId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rule-packs/installed/{{installationId}}"
            }
          },
          "response": []
        },
        {
          "name": "Upgrade an installed pack, or change its values",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"variables\": {}\n}"
            },
            "description": "The explicit action. Regenerates the pack's rules and writes the differences as ordinary revisions, so every change keeps its history. Rules the pack no longer ships are reported as orphaned and left alone rather than deleted, because you may still want the requirement.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "rule-packs",
                "installed",
                "{{installationId}}",
                "upgrade"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/rule-packs/installed/{{installationId}}/upgrade"
            }
          },
          "response": []
        }
      ],
      "name": "Rule packs"
    },
    {
      "description": "Scheduled re-audits of a site.",
      "item": [
        {
          "name": "List monitors",
          "request": {
            "description": "Returns the organisation's non-archived monitors, newest first, with the site name, the pages one run may capture and the page captures the monitor may ask for over the current month. Archived monitors are omitted.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "site_id",
                  "value": "{{site_id}}"
                }
              ],
              "raw": "{{base_url}}/v1/monitors"
            }
          },
          "response": []
        },
        {
          "name": "Get a monitor with its URL set",
          "request": {
            "description": "Returns the organisation's monitor configuration together with its configured URL set.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}"
            }
          },
          "response": []
        },
        {
          "name": "Change a monitor's name, cadence, anchor, timezone, capture profile or change policy",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"anchor_minute\": 0,\n  \"cadence\": \"manual\",\n  \"capture_profile\": {},\n  \"change_policy\": {},\n  \"mode\": \"full_site\",\n  \"name\": \"\",\n  \"timezone\": \"\",\n  \"urls\": []\n}"
            },
            "description": "A cadence, anchor or timezone change clears the next slot; the scheduler recomputes it on its next tick.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "PATCH",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}"
            }
          },
          "response": []
        },
        {
          "name": "Archive a monitor (one-way; its audits and evidence remain)",
          "request": {
            "description": "Permanently archives the organisation's monitor so it cannot be resumed or run again. Its previous audits and evidence remain subject to their existing retention policy.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}",
                "archive"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}/archive"
            }
          },
          "response": []
        },
        {
          "name": "Pause scheduling",
          "request": {
            "description": "Pauses future scheduling for the organisation's monitor. Existing audit records and captured evidence remain available under their retention policy.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}",
                "pause"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}/pause"
            }
          },
          "response": []
        },
        {
          "name": "Resume scheduling",
          "request": {
            "description": "Resumes scheduling for the organisation's non-archived monitor using its configured cadence and scope.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}",
                "resume"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}/resume"
            }
          },
          "response": []
        },
        {
          "name": "Queue an audit now with the monitor's scope frozen as the scheduler would freeze it",
          "request": {
            "description": "Admits and queues an immediate audit with the monitor's current scope, capture profile and change policy frozen into the run. It is admitted against `audit.capture` exactly as a site audit is, and a refusal is the shared billing answer. An Idempotency-Key replay returns the existing audit; archived monitors cannot run.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "disabled": true,
                "key": "Idempotency-Key",
                "value": "{{Idempotency-Key}}"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}",
                "run"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}/run"
            }
          },
          "response": []
        },
        {
          "name": "The monitor's audits, newest first",
          "request": {
            "description": "Returns audits associated with the organisation's monitor, ordered from newest to oldest.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}",
                "runs"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "status",
                  "value": "{{status}}"
                }
              ],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}/runs"
            }
          },
          "response": []
        },
        {
          "name": "Replace a url_set monitor's URL list",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"urls\": []\n}"
            },
            "description": "Makes the monitor's URL set exactly the given list and returns the monitor: a URL already in the set keeps its identity and label, a URL absent from the list is removed, and duplicates after normalisation are stored once. At most 500 URLs. Only a `url_set` monitor has a URL list; any other mode is answered 409 `not_url_set`. Historical audits keep the scope they ran with.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "PUT",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "monitors",
                "{{monitorId}}",
                "urls"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/monitors/{{monitorId}}/urls"
            }
          },
          "response": []
        }
      ],
      "name": "Monitors"
    },
    {
      "description": "Stored screenshots and other captured artifacts.",
      "item": [
        {
          "name": "Stream an authenticated raw artifact",
          "request": {
            "description": "Streams an artifact owned by the authenticated organisation using its stored media type. Expired hosted artifacts return evidence_expired rather than empty content.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "artifacts",
                "{{artifactId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/artifacts/{{artifactId}}"
            }
          },
          "response": []
        }
      ],
      "name": "Artifacts"
    },
    {
      "description": "Evidence bundle exports.",
      "item": [
        {
          "name": "List export jobs",
          "request": {
            "description": "Returns evidence export jobs for the authenticated organisation, including their recorded delivery state.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "exports"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "audit_id",
                  "value": "{{audit_id}}"
                }
              ],
              "raw": "{{base_url}}/v1/exports"
            }
          },
          "response": []
        }
      ],
      "name": "Exports"
    },
    {
      "description": "Where exports are delivered.",
      "item": [
        {
          "name": "List S3 destinations",
          "request": {
            "description": "Returns S3 destination configurations for the authenticated organisation without exposing stored access credentials.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "export-destinations"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/export-destinations"
            }
          },
          "response": []
        },
        {
          "name": "Create an encrypted S3/S3-compatible destination",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"access_key\": \"\",\n  \"bucket\": \"\",\n  \"endpoint\": \"https://example.com\",\n  \"export_mode\": \"after_every_audit\",\n  \"path_style\": false,\n  \"prefix\": \"audit\",\n  \"region\": \"\",\n  \"secret_key\": \"\",\n  \"session_token\": \"\"\n}"
            },
            "description": "Stores an S3 or S3-compatible destination for the authenticated organisation. Access credentials are encrypted before storage and are not returned by destination listings.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "export-destinations"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/export-destinations"
            }
          },
          "response": []
        },
        {
          "name": "Upload and verify a connection-test object",
          "request": {
            "description": "Uses the destination's stored credentials to upload and verify a connection-test object. A failed upload or verification returns destination_test_failed.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "export-destinations",
                "{{destinationId}}",
                "test"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/export-destinations/{{destinationId}}/test"
            }
          },
          "response": []
        }
      ],
      "name": "Export destinations"
    },
    {
      "description": "Webhook endpoints and deliveries.",
      "item": [
        {
          "name": "Page organisation webhook deliveries",
          "request": {
            "description": "Requires audit.integrations. Includes history for retired endpoints. Ordered by immutable delivery ID descending (generated UUIDv7 IDs reflect dispatch order); retrying cannot move a cursor boundary. Creation timestamps and full attempt histories were not retained and are not inferred from next_attempt_at. Lists omit payloads; use the direct detail read for the retained body and latest response.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhook-deliveries"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "status",
                  "value": "{{status}}"
                },
                {
                  "disabled": true,
                  "key": "destination",
                  "value": "{{destination}}"
                }
              ],
              "raw": "{{base_url}}/v1/webhook-deliveries"
            }
          },
          "response": []
        },
        {
          "name": "Read one organisation-owned delivery",
          "request": {
            "description": "Returns retained payload and latest response without a history scan. Requires audit.integrations.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhook-deliveries",
                "{{deliveryId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhook-deliveries/{{deliveryId}}"
            }
          },
          "response": []
        },
        {
          "name": "List lifecycle webhook endpoints",
          "request": {
            "description": "Returns the authenticated organisation's webhook endpoint configurations. Signing secrets are not included in the listing.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks"
            }
          },
          "response": []
        },
        {
          "name": "Create a signed webhook endpoint",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"events\": [],\n  \"url\": \"https://example.com\"\n}"
            },
            "description": "Registers an event delivery endpoint for the authenticated organisation and returns its new signing secret. Store the secret when creating the endpoint; subsequent listings do not disclose it.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks"
            }
          },
          "response": []
        },
        {
          "name": "Enable or disable an endpoint, or change its subscribed events",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"enabled\": false,\n  \"events\": []\n}"
            },
            "description": "Enabling clears the consecutive-failure count. An endpoint is disabled automatically after 20 consecutive failed delivery attempts; the reason is on the endpoint.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "PATCH",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks",
                "{{endpointId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks/{{endpointId}}"
            }
          },
          "response": []
        },
        {
          "name": "Retire an endpoint (soft; its delivery history is kept)",
          "request": {
            "description": "Retires the organisation's webhook endpoint from future event delivery while preserving its existing delivery history.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "DELETE",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks",
                "{{endpointId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks/{{endpointId}}"
            }
          },
          "response": []
        },
        {
          "name": "List endpoint deliveries",
          "request": {
            "description": "Without query parameters preserves the legacy 200 records ordered by next_attempt_at, including payloads. Include limit or cursor for stable descending delivery-ID pagination; paginated lists omit payloads. Default endpoint page limit is 200. Filters run before paging.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks",
                "{{endpointId}}",
                "deliveries"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                },
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "status",
                  "value": "{{status}}"
                }
              ],
              "raw": "{{base_url}}/v1/webhooks/{{endpointId}}/deliveries"
            }
          },
          "response": []
        },
        {
          "name": "Re-queue a failed delivery",
          "request": {
            "description": "Requests another attempt for a failed delivery belonging to the organisation's webhook endpoint. The response acknowledges that the retry was queued, not that delivery succeeded.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks",
                "{{endpointId}}",
                "deliveries",
                "{{deliveryId}}",
                "retry"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks/{{endpointId}}/deliveries/{{deliveryId}}/retry"
            }
          },
          "response": []
        },
        {
          "name": "Replace the endpoint's signing secret",
          "request": {
            "description": "Mints a new signing secret and returns it once; deliveries signed from now on use it, so update the receiver first if it verifies strictly.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks",
                "{{endpointId}}",
                "rotate-secret"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks/{{endpointId}}/rotate-secret"
            }
          },
          "response": []
        },
        {
          "name": "Send a signed endpoint.test event",
          "request": {
            "description": "Sends a signed endpoint.test event to the organisation's webhook endpoint and reports whether the destination accepted it.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhooks",
                "{{endpointId}}",
                "test"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/webhooks/{{endpointId}}/test"
            }
          },
          "response": []
        }
      ],
      "name": "Webhooks"
    },
    {
      "description": "The account event stream.",
      "item": [
        {
          "name": "The organisation's recent product events, newest first",
          "request": {
            "description": "Types: audit.started, audit.completed (every terminal audit, with `status`), audit.partial, audit.failed, change.detected, compliance.failed, monitor.skipped (`reason` is overlap, no_urls, or the billing code that refused the run), evidence.expiring. quota.threshold_reached and audit.quota_blocked belonged to the retired plans and are no longer emitted; subscriptions to them are accepted and receive nothing. Payloads carry counts and ids only. Webhook deliveries are created from these; each delivery is signed and carries the event id as its idempotency key.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "events"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/events"
            }
          },
          "response": []
        }
      ],
      "name": "Events"
    },
    {
      "description": "Notifications raised for the organisation.",
      "item": [
        {
          "name": "Recent notification emails and their delivery state",
          "request": {
            "description": "Returns recent notification-email records for the authenticated organisation and their recorded delivery states.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "notifications"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                }
              ],
              "raw": "{{base_url}}/v1/notifications"
            }
          },
          "response": []
        }
      ],
      "name": "Notifications"
    },
    {
      "description": "How the organisation is notified.",
      "item": [
        {
          "name": "Which events the organisation is emailed about, to whom, and whether as a daily digest",
          "request": {
            "description": "Returns the organisation's selected notification events, recipients and digest preference, together with the available event type catalogue.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "notification-preferences"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/notification-preferences"
            }
          },
          "response": []
        },
        {
          "name": "Replace the preferences",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"digest\": false,\n  \"events\": [],\n  \"recipients\": []\n}"
            },
            "description": "Recipients must be current members of the organisation, checked against Warden with the caller's own token; an API key may keep the list but not change it. Emails carry counts, names and a signed-in portal link - never captured content.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "PUT",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "notification-preferences"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/notification-preferences"
            }
          },
          "response": []
        }
      ],
      "name": "Notification preferences"
    },
    {
      "description": "Pages within an audit.",
      "item": [
        {
          "name": "A page's observation history, newest first",
          "request": {
            "description": "Returns paginated observations for a page within the authenticated organisation. Supply the returned next_cursor to continue through older observations, ordered by immutable created_at then ID descending. Lists include rule results but omit artifacts. Empty and foreign page IDs return an empty list. Repeated and unknown query parameters are rejected.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "pages",
                "{{pageId}}",
                "observations"
              ],
              "query": [
                {
                  "disabled": true,
                  "key": "limit",
                  "value": "{{limit}}"
                },
                {
                  "disabled": true,
                  "key": "cursor",
                  "value": "{{cursor}}"
                }
              ],
              "raw": "{{base_url}}/v1/pages/{{pageId}}/observations"
            }
          },
          "response": []
        }
      ],
      "name": "Pages"
    },
    {
      "description": "Per-page observations and comparisons.",
      "item": [
        {
          "name": "One observation with its artifacts and rule results",
          "request": {
            "description": "Returns an observation belonging to the authenticated organisation, including its captured artifact metadata and deterministic rule results.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "page-observations",
                "{{observationId}}"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/page-observations/{{observationId}}"
            }
          },
          "response": []
        },
        {
          "name": "What changed against the observation before it",
          "request": {
            "description": "Computed from stored evidence under the audit's change policy - normalised text hunks (whitespace collapsed, numbers masked, ignored selectors removed), scores, URL/title/status changes, rule transitions and screenshot artifact ids for each side. The raw artifacts are untouched. A first capture has no previous side and says why.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "page-observations",
                "{{observationId}}",
                "comparison"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/page-observations/{{observationId}}/comparison"
            }
          },
          "response": []
        }
      ],
      "name": "Page observations"
    },
    {
      "description": "This month's metered use, capacity and hosted evidence.",
      "item": [
        {
          "name": "Tenant-scoped setup facts and recent activity for the portal",
          "request": {
            "description": "Returns setup counts and recent activity for the authenticated organisation. Activity labels omit site URLs, captured content and credentials.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "home"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/home"
            }
          },
          "response": []
        },
        {
          "name": "This month's metered use, capacity and hosted evidence",
          "request": {
            "description": "The month (UTC) as the organisation's billing account has it for Ironfang\nAudit's meters - `captures` (`audit.capture`) and `retention_extension`\n(`audit.retention_extension`): the free allowance, what has been settled,\nwhat admitted audits still hold, and the charge so far before tax. Both are\nnull where unified billing is not running (`billing_enabled` false): audits\nare then admitted on capacity alone and nothing is metered. Beside them, the\nfacts that are not billing: `sites` against `site_limit` and\n`max_pages_per_audit` (capacity limits, the same for everyone), the\nstandard hosted retention new audits get, hosted bytes and the next expiry,\nthe `projection` of captures the active scheduled monitors may ask for this\nmonth (pages x runs, an upper bound), and `daily` captures by UTC day of\nadmission. `quota` is deprecated: the launch-era shape, now captures\nagainst the month's free allowance only.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "usage"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/usage"
            }
          },
          "response": []
        }
      ],
      "name": "Usage"
    },
    {
      "description": "Quoted, fixed-price extensions of hosted evidence retention.",
      "item": [
        {
          "name": "Buy a retention quote",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"quote_id\": \"00000000-0000-0000-0000-000000000000\"\n}"
            },
            "description": "Buys a quote exactly as quoted, in one step: the quoted quantity of\n`audit.retention_extension` is admitted by the billing account, every\nquoted deadline moves to its quoted date, and the usage is committed -\nall of it or none. Needs billing.manage from a signed-in person with a\nverified email address: API keys and connected apps are refused\n(`insufficient_scope`, `person_required`), as for every billing change.\nA refusal from the billing account (paid usage not enabled, a budget\nreached) is the shared billing answer. A quote past its `expires_at`,\nmade in another month or at another catalogue version, that the\naccount's position would now price differently, or whose evidence has\nchanged since (deleted, or its deadline moved) is `quote_expired`: ask\nfor a new quote. Buying a quote that is already bought returns it with\n200 and charges nothing more.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "retention",
                "purchases"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/retention/purchases"
            }
          },
          "response": []
        },
        {
          "name": "Price an extension of hosted evidence retention",
          "request": {
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"artifact_ids\": [],\n  \"audit_ids\": [],\n  \"months\": 1\n}"
            },
            "description": "Prices keeping the hosted evidence of the chosen audits (every hosted\nartifact of each) and artifacts for `months` whole months past each one's\ncurrent deadline. New audits are promised the standard retention (30 days\nin the draft catalogue); an extension is how evidence stays hosted longer.\nThe quantity is in the `audit.retention_extension` meter's unit: the\nselection's bytes rounded up to that unit's share of a decimal gigabyte,\ntimes the months, never below ten GB-months. `amount` is the fixed price of\nthat quantity at the organisation's position this month, exact and before\ntax, charged on the month's invoice through the billing account. A quote\ncan be bought until `expires_at` (about fifteen minutes), in the month and\nat the catalogue version it was made in; it moves nothing and charges\nnothing by itself, and nothing ever renews. Expired (deleted) evidence\ncannot be extended. An extension that would take the storage held under\nextended retention past the deployment's capacity is refused, paid or not.\nNeeds audit.read: a quote is a price, not a purchase.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "retention",
                "quotes"
              ],
              "query": [],
              "raw": "{{base_url}}/v1/retention/quotes"
            }
          },
          "response": []
        }
      ],
      "name": "Retention"
    },
    {
      "description": "Public verification of evidence bundles.",
      "item": [
        {
          "name": "Verify an Ironfang Audit evidence ZIP",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "body": {
              "file": {
                "src": ""
              },
              "mode": "file"
            },
            "description": "Accepts an evidence ZIP without requiring an account and checks its integrity, signature and timestamp trust. Invalid evidence returns a verification report with status 422; successful verification does not assert that the audited website complies with any law.\n\nSelect the file to send in Body.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/zip"
              }
            ],
            "method": "POST",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "verify",
                "v1",
                "bundles"
              ],
              "query": [],
              "raw": "{{base_url}}/verify/v1/bundles"
            }
          },
          "response": []
        },
        {
          "name": "List the Ironfang Audit signing-key ledger",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "description": "Publishes the public signing-key ledger and lifecycle metadata used to inspect Ironfang Audit evidence signatures. Authentication is not required and private signing keys are never returned.",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET",
            "url": {
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "verify",
                "v1",
                "signing-keys"
              ],
              "query": [],
              "raw": "{{base_url}}/verify/v1/signing-keys"
            }
          },
          "response": []
        }
      ],
      "name": "Verify"
    }
  ],
  "variable": [
    {
      "key": "Idempotency-Key",
      "type": "string",
      "value": ""
    },
    {
      "key": "artifactId",
      "type": "string",
      "value": ""
    },
    {
      "key": "assignee",
      "type": "string",
      "value": ""
    },
    {
      "key": "auditId",
      "type": "string",
      "value": ""
    },
    {
      "key": "audit_id",
      "type": "string",
      "value": ""
    },
    {
      "key": "base_url",
      "type": "string",
      "value": "https://api.ironfang.com/audit"
    },
    {
      "key": "capture",
      "type": "string",
      "value": ""
    },
    {
      "key": "change",
      "type": "string",
      "value": ""
    },
    {
      "key": "compliance",
      "type": "string",
      "value": ""
    },
    {
      "key": "cursor",
      "type": "string",
      "value": ""
    },
    {
      "key": "deliveryId",
      "type": "string",
      "value": ""
    },
    {
      "key": "destination",
      "type": "string",
      "value": ""
    },
    {
      "key": "destinationId",
      "type": "string",
      "value": ""
    },
    {
      "key": "endpointId",
      "type": "string",
      "value": ""
    },
    {
      "key": "findingId",
      "type": "string",
      "value": ""
    },
    {
      "key": "installationId",
      "type": "string",
      "value": ""
    },
    {
      "key": "limit",
      "type": "string",
      "value": ""
    },
    {
      "key": "lineageId",
      "type": "string",
      "value": ""
    },
    {
      "key": "monitorId",
      "type": "string",
      "value": ""
    },
    {
      "key": "observationId",
      "type": "string",
      "value": ""
    },
    {
      "key": "offset",
      "type": "string",
      "value": ""
    },
    {
      "key": "open_longer_than_days",
      "type": "string",
      "value": ""
    },
    {
      "key": "pageId",
      "type": "string",
      "value": ""
    },
    {
      "key": "page_id",
      "type": "string",
      "value": ""
    },
    {
      "key": "q",
      "type": "string",
      "value": ""
    },
    {
      "key": "rule_id",
      "type": "string",
      "value": ""
    },
    {
      "key": "severity",
      "type": "string",
      "value": ""
    },
    {
      "key": "siteId",
      "type": "string",
      "value": ""
    },
    {
      "key": "site_id",
      "type": "string",
      "value": ""
    },
    {
      "key": "sort",
      "type": "string",
      "value": ""
    },
    {
      "key": "state",
      "type": "string",
      "value": ""
    },
    {
      "key": "status",
      "type": "string",
      "value": ""
    }
  ]
}
