API v1

Audits, programmatically.

One endpoint to queue a scan, one to poll it. Bearer-token auth, JSON in, JSON out. Available on Pro and Agency.

Authentication

Create a token in Account → API tokens and send it as a bearer token. The plaintext is shown once, at creation — we store only its hash.

curl https://makeitflow.si/api/v1/me \
  -H "Authorization: Bearer ibmb_your_token_here" \
  -H "Accept: application/json"

A missing or unknown token returns 401. A valid token on a plan without API access returns 403.

Endpoints

All paths are relative to https://makeitflow.si/api/v1.

Method Path Description Requires
GET /me Your plan, entitlements and remaining allowance. Pro
POST /scans Queue an audit. Returns 202, or 200 with a recent one. Pro
GET /scans List your scans. Filter by host and status. Pro
GET /scans/{id} Read one scan. Add ?include=checks for the full breakdown. Pro
DELETE /scans/{id} Delete a scan and its stored result. Pro
POST /batches Queue up to 100 audits at once. Agency
GET /batches List your batches with progress. Agency
GET /batches/{id} Read one batch, including every scan in it. Agency
DELETE /batches/{id} Remove the grouping. The reports themselves are kept. Agency
POST /crawls Crawl a whole site. Returns 202 with the crawl id. Pro
GET /crawls List your crawls with page counts and status. Pro
GET /crawls/{id} Read one crawl. Add ?include=pages for every URL found. Pro
GET /crawls/{id}/map The internal link graph as nodes and edges. Pro
DELETE /crawls/{id} Delete a crawl and everything found in it. Pro

Queue a scan

Audits run asynchronously — the response comes back immediately with status: "queued". Poll the links.self URL until status is completed or failed. A scan usually takes 20–40 seconds.

curl -X POST https://makeitflow.si/api/v1/scans \
  -H "Authorization: Bearer ibmb_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"url": "example.com", "strategy": "mobile"}'

202 Accepted

{
  "data": {
    "id": "642cad1f-da06-4b19-8941-11c47c60007f",
    "url": "https://example.com",
    "host": "example.com",
    "strategy": "mobile",
    "status": "queued",
    "visibility": "unlisted",
    "scores": { "overall": null, "grade": null, ... },
    "links": {
      "self": "https://makeitflow.si/api/v1/scans/642cad1f-…",
      "html": "https://makeitflow.si/report/642cad1f-…",
      "pdf":  "https://makeitflow.si/report/642cad1f-…/pdf"
    }
  },
  "message": "Scan queued. Poll the self link until status is completed or failed."
}

Two behaviours worth knowing

  • Recent-scan reuse. Re-submitting the same target inside the cooldown window returns 200 with the existing report instead of re-running it. Send "force": true to insist on a fresh audit.
  • Private targets are refused. Only public web addresses can be audited. A hostname that resolves to a private, loopback or reserved address is rejected — at submission when it is obvious, otherwise as a failed scan with the reason in failure_reason.

Bulk scanning Agency

Submit up to 100 URLs in one call. Each becomes an ordinary report with its own link and PDF; the batch exists to give them a name and one progress figure.

curl -X POST https://makeitflow.si/api/v1/batches \
  -H "Authorization: Bearer ibmb_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
        "label": "Q3 client portfolio",
        "urls": ["clienta.com", "clientb.com", "clientc.com"]
      }'

Unrecognised entries are never silently dropped — they come back in skipped, and anything beyond your per-batch limit in truncated.

Webhooks

Rather than polling, register a callback URL in Account → Webhooks and we'll POST to it the moment an audit finishes. Events: scan.completed, scan.failed, batch.completed.

Request we send

POST /your/handler
Content-Type: application/json
X-IBMB-Event: scan.completed
X-IBMB-Delivery: 9f2c1e7a-…            # unique per delivery, safe to dedupe on
X-IBMB-Timestamp: 1785000000
X-IBMB-Signature: sha256=4f8c…

{
  "event": "scan.completed",
  "created_at": "2026-07-31T01:03:08+00:00",
  "data": { "scan": { …same shape as GET /scans/{id}?include=checks… } }
}

Verifying the signature

The HMAC is computed over "{timestamp}.{raw body}" using your endpoint's signing secret. Compare in constant time, and reject anything older than a few minutes — the timestamp is inside the signed material precisely so a captured payload cannot be replayed later with a fresh header.

$timestamp = $request->header('X-IBMB-Timestamp');
$expected  = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $request->getContent(), $secret);

abort_unless(hash_equals($expected, $request->header('X-IBMB-Signature')), 401);
abort_if(abs(time() - (int) $timestamp) > 300, 401);

Delivery behaviour

  • Answer any 2xx to acknowledge. Anything else is retried 4 times with backoff (10s, 1m, 5m, 15m).
  • Redirects are never followed. Point us at the final URL.
  • After 10 consecutive failures the endpoint is disabled automatically and the reason is shown in your dashboard — re-enable it there once fixed.
  • Retries mean a delivery can arrive more than once. Deduplicate on X-IBMB-Delivery and treat handlers as idempotent.
  • The last 50 deliveries per endpoint are logged with status and error, so you can debug your own handler without asking us.

Rate limits

  • 120 requests / minute overall.
  • 20 / minute for scan and batch creation.
  • Counted per account, not per IP.
  • Your plan's daily scan allowance applies on top — check it at /me.

Errors

  • 401 — token missing, unknown or expired.
  • 403 — your plan does not include this.
  • 404 — no such scan on your account.
  • 422 — validation failed; see errors.
  • 429 — rate limit or daily allowance reached.

Ready to wire it up?

API access is included on Pro and Agency, alongside white-label reports and monitoring.

See plans