API Reference
The middleBrick REST API lets you integrate security scanning into any system: internal tools, Slack bots, dashboards, CI pipelines, or custom automations.
Base URL
Section titled “Base URL”https://api.middlebrick.com/v1Authentication
Section titled “Authentication”All API requests require an API key passed in the Authorization header:
Authorization: Bearer mb_your_api_key_hereGenerate API keys from your dashboard. Keys inherit your plan’s rate limits and scan quotas.
Endpoints
Section titled “Endpoints”POST /scan
Section titled “POST /scan”Submit a URL for security scanning.
Request:
curl -X POST https://api.middlebrick.com/v1/scan \ -H "Authorization: Bearer mb_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "url": "https://api.example.com/v1/users", "specUrl": "https://api.example.com/openapi.json", "context": "financial" }'Request body:
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The API endpoint URL to scan (must be HTTPS) |
specUrl | string | No | OpenAPI/Swagger spec URL for deeper analysis |
context | string | No | API context: financial, medical, public, internal |
Response (200):
{ "id": "scan_abc123", "status": "completed", "url": "https://api.example.com/v1/users", "score": 72, "grade": "C", "createdAt": "2025-01-15T10:30:00Z", "completedAt": "2025-01-15T10:30:08Z", "categories": { "authentication": { "score": 85, "findings": [ { "severity": "high", "title": "Auth bypass via HTTP method", "description": "POST returns 200 without credentials while GET requires auth", "remediation": "Enforce authentication across all HTTP methods" } ] }, "bolaAuthorization": { "score": 60, "findings": [...] }, "bflaAuthorization": { "score": 100, "findings": [] }, "propertyAuthorization": { "score": 90, "findings": [...] }, "inputValidation": { "score": 75, "findings": [...] }, "rateLimiting": { "score": 50, "findings": [...] }, "dataExposure": { "score": 65, "findings": [...] }, "encryption": { "score": 95, "findings": [] }, "ssrf": { "score": 100, "findings": [] }, "inventoryManagement": { "score": 80, "findings": [...] }, "unsafeConsumption": { "score": 100, "findings": [] }, "llmSecurity": { "score": 100, "findings": [] } }, "findings": [ { "category": "authentication", "severity": "high", "title": "Auth bypass via HTTP method", "description": "POST returns 200 without credentials while GET requires auth", "remediation": "Enforce authentication across all HTTP methods" }, { "category": "dataExposure", "severity": "high", "title": "PII detected in response", "description": "Email addresses found in response body", "remediation": "Remove or mask PII from API responses" } ]}Response fields:
| Field | Type | Description |
|---|---|---|
id | string | Unique scan identifier |
status | string | completed, failed, or processing |
url | string | The scanned URL |
score | number | Overall security score (0–100) |
grade | string | Letter grade: A, B, C, D, or F |
createdAt | string | ISO 8601 timestamp of scan creation |
completedAt | string | ISO 8601 timestamp of scan completion |
categories | object | Per-category scores and findings |
findings | array | All findings sorted by severity |
Finding object:
| Field | Type | Description |
|---|---|---|
category | string | Which security check produced this finding |
severity | string | critical, high, medium, low, or info |
title | string | Short description of the finding |
description | string | Detailed explanation |
remediation | string | How to fix the issue |
GET /scan/:id
Section titled “GET /scan/:id”Retrieve results for a previous scan.
Request:
curl https://api.middlebrick.com/v1/scan/scan_abc123 \ -H "Authorization: Bearer mb_your_api_key_here"Response: Same format as POST /scan response.
Returns 404 if the scan doesn’t exist or doesn’t belong to your account.
GET /scans
Section titled “GET /scans”List your scan history, newest first.
Request:
curl "https://api.middlebrick.com/v1/scans?limit=10&offset=0" \ -H "Authorization: Bearer mb_your_api_key_here"Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Results per page (max 100) |
offset | number | 0 | Pagination offset |
Response (200):
{ "scans": [ { "id": "scan_abc123", "url": "https://api.example.com/v1/users", "score": 72, "grade": "C", "findingsCount": 7, "createdAt": "2025-01-15T10:30:00Z" }, { "id": "scan_def456", "url": "https://api.example.com/v1/health", "score": 91, "grade": "A", "findingsCount": 2, "createdAt": "2025-01-14T08:15:00Z" } ], "total": 42, "limit": 20, "offset": 0}Rate Limits
Section titled “Rate Limits”Rate limits are enforced per API key:
| Plan | Requests/minute | Scans/month |
|---|---|---|
| Free | 10 | 3 |
| Starter | 30 | 15 |
| Pro | 60 | 100 |
| Enterprise | Custom | Unlimited |
When you hit a rate limit, the API returns 429 Too Many Requests with a Retry-After header indicating when you can retry.
Rate limit headers (included in every response):
| Header | Description |
|---|---|
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Errors
Section titled “Errors”All errors follow this format:
{ "error": { "code": "rate_limit_exceeded", "message": "You have exceeded your plan's scan limit" }}| Code | HTTP Status | Description |
|---|---|---|
invalid_url | 400 | The provided URL is not valid or not HTTPS |
invalid_context | 400 | Context must be one of: financial, medical, public, internal |
unauthorized | 401 | Missing or invalid API key |
forbidden | 403 | Your plan doesn’t include this feature |
not_found | 404 | Scan not found or doesn’t belong to your account |
rate_limit_exceeded | 429 | Plan limit reached (check Retry-After header) |
scan_failed | 500 | Scan could not complete (target unreachable or returned error) |
Code Examples
Section titled “Code Examples”JavaScript / Node.js
Section titled “JavaScript / Node.js”const response = await fetch('https://api.middlebrick.com/v1/scan', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.MIDDLEBRICK_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://api.example.com/v1/users', context: 'financial', }),});
const result = await response.json();console.log(`Score: ${result.score} (${result.grade})`);console.log(`Findings: ${result.findings.length}`);
// Show critical findingsresult.findings .filter(f => f.severity === 'critical') .forEach(f => console.log(`CRITICAL: ${f.title}`));Python
Section titled “Python”import osimport requests
response = requests.post( 'https://api.middlebrick.com/v1/scan', headers={ 'Authorization': f'Bearer {os.environ["MIDDLEBRICK_API_KEY"]}', 'Content-Type': 'application/json', }, json={ 'url': 'https://api.example.com/v1/users', 'context': 'financial', },)
result = response.json()print(f'Score: {result["score"]} ({result["grade"]})')
for finding in result['findings']: if finding['severity'] in ('critical', 'high'): print(f'[{finding["severity"].upper()}] {finding["title"]}')cURL — scan and extract score
Section titled “cURL — scan and extract score”# One-liner: scan and show scorecurl -s -X POST https://api.middlebrick.com/v1/scan \ -H "Authorization: Bearer $MIDDLEBRICK_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://api.example.com/v1/users"}' \ | jq '{score, grade, findings: [.findings[] | {severity, title}]}'