Developers
The Hardn REST API. Scan from CI.
Register sites, prove ownership, start scans and read findings as JSON. The same ownership rules and credits as the app.
Your first scan is free, no card needed. You prove you own the site before Hardn touches it.
Authentication
Create a key in the app under API keys (owners and admins). Send it as a bearer token. Keys start with hk_live_, belong to one organisation, and are shown only once.
Authorization: Bearer hk_live_…| Base URL | https://api.hardn.si/v1 |
|---|---|
| Site ids | tgt_… |
| Scan ids | asm_… |
| Times | ISO-8601, UTC |
Quick start
Four calls from a new site to its report.
1. Register your site
bash curl -s https://api.hardn.si/v1/targets \ -H "Authorization: Bearer $HARDN_KEY" -H "Content-Type: application/json" \ -d '{"url": "https://app.example.com", "kind": "website"}'2. Add the DNS record from instructions.dns_txt, then verify
bash curl -s -X POST https://api.hardn.si/v1/targets/tgt_…/verify -H "Authorization: Bearer $HARDN_KEY"3. Start a scan and poll it
bash curl -s https://api.hardn.si/v1/scans -H "Authorization: Bearer $HARDN_KEY" -H "Content-Type: application/json" \ -d '{"target_id": "tgt_…", "scan_type": "public"}'curl -s https://api.hardn.si/v1/scans/asm_… -H "Authorization: Bearer $HARDN_KEY"4. Read the report
bash curl -s "https://api.hardn.si/v1/scans/asm_…/report?format=json" -H "Authorization: Bearer $HARDN_KEY"
Routes
Every route is scoped to the key's organisation.
| Route | Body → result |
|---|---|
| POST/targets | {"url": "https://app.example.com", "kind": "website"}201 — the site, with verification_token and instructions (DNS and file). |
| GET/targets | Your organisation's sites. |
| POST/targets/{id}/verify | {"status", "verified", "detail"} — runs the DNS or file check now. |
| POST/targets/{id}/accounts | {"label", "level", "tenant", "auth_type", "secret", "header_name"}201 — a deep-scan test account. Secrets are write-only. |
| POST/scans | {"target_id": "tgt_…", "scan_type": "public"}201 — the scan, queued. 409 target_unverified, 402 insufficient_credits. |
| GET/scans/{id} | Status, progress, and when completed: score, grade and counts. |
| GET/scans/{id}/findings | Every finding with severity, evidence and the fix. |
| GET/scans/{id}/report?format=json|html | The full report and fix report. |
Errors
Errors are JSON: {"detail": {"code": "…", "message": "…"}}.
| Status and code | What it means |
|---|---|
| 401 unauthenticated | Missing, wrong or revoked API key. |
| 402 insufficient_credits | The organisation has no scan credits left. |
| 404 not_found | The id doesn't exist or belongs to another organisation. |
| 409 target_unverified | Ownership hasn't been proved, or the proof has gone. |
| 422 validation_error | The body is invalid; errors lists each field. |
| 429 rate_limited | Slow down and retry after a moment. |
Use it in CI
Store the key as a secret, start a scan after each deploy, and fail the job if the grade drops below what you accept.
- name: Hardn scan env: { HARDN_KEY: ${{ secrets.HARDN_KEY }} } run: | ID=$(curl -s https://api.hardn.si/v1/scans -H "Authorization: Bearer $HARDN_KEY" \ -H "Content-Type: application/json" \ -d '{"target_id": "tgt_…", "scan_type": "public"}' | jq -r .id) while :; do SCAN=$(curl -s https://api.hardn.si/v1/scans/$ID -H "Authorization: Bearer $HARDN_KEY") case "$(echo "$SCAN" | jq -r .status)" in queued|running) sleep 15;; *) break;; esac done GRADE=$(echo "$SCAN" | jq -r .grade) case "$GRADE" in A|B) ;; *) echo "Hardn grade $GRADE"; exit 1;; esacCreate a free account to get a key.
Scan from your pipeline this week
Add your site, prove you own it, and Hardn runs 27 read-only checks. You get a grade, every issue it found and the steps to fix each one. Your first scan is free.