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
200with the existing report instead of re-running it. Send"force": trueto 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-Deliveryand 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; seeerrors.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