Ironbark API Reference
Ironbark is Australia's compliance intelligence layer — machine-to-machine first. Agents and applications call Ironbark to screen entities against PEP and sanctions lists, run AML risk assessments, manage compliance cases, and export regulator-ready PDF reports.
Base URL
https://api.ironbarkaml.com.au
All endpoints are versioned under /v1. ACP endpoints use the /acp prefix.
Why Ironbark vs NameScan
| Feature | NameScan | Ironbark |
|---|---|---|
| Scan + risk in one call | 2 API calls | 1 call — POST /v1/scans/full |
| GET scan by ID | Added in v3.1 only | Day 1, all entity types |
| Credit expiry | 12 months (top complaint) | Never expire |
| AU-native data | None | ASIC, AUSTRAC, ABN (Phase 2+) |
| Auth | Static API key | OAuth 2.0 client credentials |
| Rate limit transparency | Undocumented | Explicit headers on every response |
| PDF reports | Bundled, no API | GET /v1/cases/{id}/report |
Authentication
Ironbark uses OAuth 2.0 client credentials (RFC 6749 §4.4).
Exchange your client_id and client_secret for a Bearer token,
then pass that token in the Authorization header on every API call.
X-Api-Key-Expires header on every response tells you when your client registration expires.
Request must be application/x-www-form-urlencoded.
| Field | Type | Required | Description |
|---|---|---|---|
grant_type | string | Required | Must be client_credentials |
client_id | string | Required | UUID issued at registration |
client_secret | string | Required | Plaintext secret issued at registration (shown once) |
Response
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "scans:read scans:write cases:read cases:write reports:read"
}
Available Scopes
| Scope | Grants access to |
|---|---|
scans:read | GET /v1/scans/{id}, GET /v1/scans/batch/{id} |
scans:write | POST /v1/scans/full, POST /v1/scans/batch |
cases:read | GET /v1/cases/{id} |
cases:write | POST /v1/cases, PATCH /v1/cases/{id}/decision |
reports:read | GET /v1/cases/{id}/report |
monitoring:write | Ongoing monitoring enrolment (Phase 3) |
Code Examples
import requests
response = requests.post(
"https://api.ironbarkaml.com.au/v1/oauth/token",
data={
"grant_type": "client_credentials",
"client_id": "your_client_id",
"client_secret": "your_client_secret",
},
)
response.raise_for_status()
token = response.json()["access_token"]
# Use token in subsequent requests
headers = {"Authorization": f"Bearer {token}"}
const res = await fetch(
"https://api.ironbarkaml.com.au/v1/oauth/token",
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: "your_client_id",
client_secret: "your_client_secret",
}),
}
);
const { access_token } = await res.json();
// Use token in subsequent requests
const headers = { Authorization: `Bearer ${access_token}` };
require 'net/http'
require 'json'
uri = URI('https://api.ironbarkaml.com.au/v1/oauth/token')
res = Net::HTTP.post_form(uri, {
'grant_type' => 'client_credentials',
'client_id' => 'your_client_id',
'client_secret' => 'your_client_secret'
})
token = JSON.parse(res.body)['access_token']
# Use token in subsequent requests
headers = { 'Authorization' => "Bearer #{token}" }
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String body = "grant_type=client_credentials"
+ "&client_id=your_client_id"
+ "&client_secret=your_client_secret";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.ironbarkaml.com.au/v1/oauth/token"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// Parse access_token from response.body() with a JSON library
curl -X POST https://api.ironbarkaml.com.au/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=YOUR_ID&client_secret=YOUR_SECRET"
Rate Limits
Rate limits are enforced per OAuth client on a per-minute sliding window, tracked in Redis. If Redis is unavailable, rate limiting degrades gracefully — requests are allowed through rather than blocked. Limits reset at the start of each UTC minute.
| Plan | Requests / minute | Batch entities / request |
|---|---|---|
| Free | 10 | 10 |
| Starter ($99/mo) | 60 | 50 |
| Builder ($299/mo) | 200 | 100 |
| Scale ($799/mo) | 1,000 | 100 |
| Enterprise | Custom | 100 |
When a rate limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating the seconds until the window resets.
Rate limit response (429)
{
"detail": "Rate limit exceeded"
}
Headers:
Retry-After: 47
Response Headers
Every authenticated response (including error responses from authenticated routes) includes the following headers. These are injected by the API middleware, not the route handler.
| Header | Example | Description |
|---|---|---|
X-Api-Key-Expires |
2026-06-30T00:00:00+00:00 |
ISO 8601 timestamp when your client registration expires. Value is never for non-expiring clients. |
X-RateLimit-Limit |
60 |
Maximum requests permitted in the current 1-minute window for your client. |
X-RateLimit-Remaining |
54 |
Requests remaining in the current window. Never negative. |
X-RateLimit-Reset |
1743123660 |
Unix timestamp (UTC) of when the current window resets. |
Full Scan
Screen a person or organisation against PEP lists, sanctions databases, and adverse media.
Returns a combined scan result + AML risk assessment in a single call.
The scan_id in the response is permanent — retrieve it any time with
GET /v1/scans/{scan_id}.
Request Body
| Field | Type | Description | |
|---|---|---|---|
entity_type | string | Required | "person" or "organisation" |
name | string | Required | Full legal name. Max 512 chars. |
dob | string | Optional | Date of birth YYYY-MM-DD. Person only. Improves match precision. |
gender | string | Optional | "M", "F", or "X". Person only. |
nationality_code | string | Optional | ISO 3166-1 alpha-2 country code. Person only. |
incorporation_country_code | string | Optional | ISO 3166-1 alpha-2. Organisation only. |
country_code | string | Optional | Country of operation. Affects risk scoring. |
risk_profile | object | Optional | AML context. See risk profile tables below. |
Person Risk Profile (risk_profile when entity_type = "person")
| Field | Type | Default | Values |
|---|---|---|---|
resident_status | string | "resident" | "resident" | "non_resident" |
profession | string | null | e.g. "accountant", "lawyer", "financial_advisor" |
client_visit_type | string | "face_to_face" | "face_to_face" | "non_face_to_face" |
Organisation Risk Profile (risk_profile when entity_type = "organisation")
| Field | Type | Default | Description |
|---|---|---|---|
legal_status | string | null | e.g. "private_company", "trust", "shell" |
industry_type | string | null | e.g. "financial_services", "gambling", "real_estate" |
has_sanctions | boolean | false | True if any officer/director is on a sanctions list |
is_sanctioned | boolean | false | True if the entity itself is on a sanctions list |
is_high_risk_country | boolean | false | True if entity operates in a FATF high-risk jurisdiction |
Response
{
"scan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"entity_type": "person",
"entity_name": "Anthony Albanese",
"created_at": "2026-03-28T12:00:00+00:00",
"scan_result": {
"match_count": 0,
"matches": [],
"filter_applied": false,
"filter_explanation": null,
"source_staleness": "fresh",
"sources_checked": ["dfat_au", "ofac_us", "un_consolidated"]
},
"risk_assessment": {
"risk_level": "low",
"risk_score": 12,
"risk_factors": [],
"recommendation": "Standard due diligence sufficient"
},
"metadata": {
"service_id": "ironbark_scan_v1",
"query_time_ms": 84,
"data_sources": ["dfat_au", "ofac_us", "un_consolidated"]
}
}
Code Examples
response = requests.post(
"https://api.ironbarkaml.com.au/v1/scans/full",
headers={"Authorization": f"Bearer {token}"},
json={
"entity_type": "person",
"name": "Anthony Albanese",
"dob": "1963-03-02",
"nationality_code": "AU",
"risk_profile": {
"resident_status": "resident",
"profession": "politician",
"client_visit_type": "non_face_to_face",
},
},
)
scan = response.json()
print(scan["scan_id"], scan["risk_assessment"]["risk_level"])
const scan = await fetch(
"https://api.ironbarkaml.com.au/v1/scans/full",
{
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
entity_type: "person",
name: "Anthony Albanese",
dob: "1963-03-02",
nationality_code: "AU",
risk_profile: {
resident_status: "resident",
profession: "politician",
client_visit_type: "non_face_to_face",
},
}),
}
).then(r => r.json());
console.log(scan.scan_id, scan.risk_assessment.risk_level);
require 'net/http'
require 'json'
uri = URI('https://api.ironbarkaml.com.au/v1/scans/full')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri.path, {
'Authorization' => "Bearer #{token}",
'Content-Type' => 'application/json'
})
req.body = {
entity_type: 'person',
name: 'Anthony Albanese',
dob: '1963-03-02',
nationality_code: 'AU'
}.to_json
scan = JSON.parse(http.request(req).body)
String body = """
{
"entity_type": "person",
"name": "Anthony Albanese",
"dob": "1963-03-02",
"nationality_code": "AU"
}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.ironbarkaml.com.au/v1/scans/full"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(req,
HttpResponse.BodyHandlers.ofString());
curl -X POST https://api.ironbarkaml.com.au/v1/scans/full \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entity_type": "person",
"name": "Anthony Albanese",
"dob": "1963-03-02",
"nationality_code": "AU",
"risk_profile": {
"resident_status": "resident",
"profession": "politician"
}
}'
Get Scan
Retrieve a previously executed scan by its ID. Idempotent — calling this multiple times never re-bills or re-executes the scan. Returns the original result exactly as delivered.
| Parameter | In | Description |
|---|---|---|
scan_id | path | UUID from the original POST /v1/scans/full response |
Code Examples
scan_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
response = requests.get(
f"https://api.ironbarkaml.com.au/v1/scans/{scan_id}",
headers={"Authorization": f"Bearer {token}"},
)
scan = response.json()
const scanId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
const scan = await fetch(`https://api.ironbarkaml.com.au/v1/scans/${scanId}`, {
headers: { Authorization: `Bearer ${token}` },
}).then(r => r.json());
scan_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
uri = URI("https://api.ironbarkaml.com.au/v1/scans/#{scan_id}")
req = Net::HTTP::Get.new(uri, { 'Authorization' => "Bearer #{token}" })
scan = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }.body)
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.ironbarkaml.com.au/v1/scans/" + scanId))
.header("Authorization", "Bearer " + token)
.GET()
.build();
HttpResponse<String> response = client.send(req,
HttpResponse.BodyHandlers.ofString());
curl https://api.ironbarkaml.com.au/v1/scans/SCAN_ID \
-H "Authorization: Bearer YOUR_TOKEN"
Filter Behaviour
When optional fields like dob, nationality_code, or gender
are supplied, the scan engine applies post-match filters to reduce false positives.
Every scan response transparently reports whether filtering was applied and why.
| Field | Type | Description |
|---|---|---|
scan_result.filter_applied |
boolean |
true if one or more filters reduced the raw match set.
false if all raw matches are returned as-is.
|
scan_result.filter_explanation |
string | null |
Human-readable description of which filters were applied.
Example: "DOB filter removed 2 candidate matches"
|
filter_explanation gives you a ready-made audit trail string — no extra logic required.
Filter priority
- DOB exact match — highest precision, applied first
- Gender filter — applied when DOB is absent or ambiguous
- Nationality filter — applied as a secondary tiebreaker
- Country of operation — lowest priority, signals regional relevance only
Example — filter applied
{
"scan_result": {
"match_count": 1,
"filter_applied": true,
"filter_explanation": "DOB filter removed 3 candidate matches; 1 remaining",
"matches": [{ /* ... */ }]
}
}
Submit Batch Scan
Submit up to 100 entities for asynchronous scanning. Returns
202 Accepted immediately with a job_id. Processing runs in
the background — poll GET /v1/scans/batch/{job_id}
for status, or supply a webhook_url to receive a batch.completed event.
Request Body
| Field | Type | Description | |
|---|---|---|---|
entities | array | Required | 1–100 entity objects. Each has the same fields as POST /v1/scans/full. |
webhook_url | string | Optional | HTTPS URL. Receives batch.completed event when all items finish. |
Code Examples
response = requests.post(
"https://api.ironbarkaml.com.au/v1/scans/batch",
headers={"Authorization": f"Bearer {token}"},
json={
"entities": [
{"entity_type": "person", "name": "John Smith", "nationality_code": "AU"},
{"entity_type": "organisation", "name": "Acme Pty Ltd", "country_code": "AU"},
],
"webhook_url": "https://yourapp.com/webhooks/ironbark",
},
)
job_id = response.json()["job_id"]
const { job_id } = await fetch(
"https://api.ironbarkaml.com.au/v1/scans/batch",
{
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
entities: [
{ entity_type: "person", name: "John Smith", nationality_code: "AU" },
{ entity_type: "organisation", name: "Acme Pty Ltd", country_code: "AU" },
],
webhook_url: "https://yourapp.com/webhooks/ironbark",
}),
}
).then(r => r.json());
uri = URI('https://api.ironbarkaml.com.au/v1/scans/batch')
req = Net::HTTP::Post.new(uri, {
'Authorization' => "Bearer #{token}",
'Content-Type' => 'application/json'
})
req.body = {
entities: [
{ entity_type: 'person', name: 'John Smith', nationality_code: 'AU' }
],
webhook_url: 'https://yourapp.com/webhooks/ironbark'
}.to_json
result = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }.body)
job_id = result['job_id']
String body = """
{
"entities": [
{"entity_type": "person", "name": "John Smith", "nationality_code": "AU"},
{"entity_type": "organisation", "name": "Acme Pty Ltd", "country_code": "AU"}
],
"webhook_url": "https://yourapp.com/webhooks/ironbark"
}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.ironbarkaml.com.au/v1/scans/batch"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
curl -X POST https://api.ironbarkaml.com.au/v1/scans/batch \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entities": [
{"entity_type": "person", "name": "John Smith", "nationality_code": "AU"},
{"entity_type": "organisation", "name": "Acme Pty Ltd", "country_code": "AU"}
],
"webhook_url": "https://yourapp.com/webhooks/ironbark"
}'
Response (202 Accepted)
{
"job_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"status": "pending",
"total_items": 2,
"completed_items": 0,
"failed_items": 0,
"webhook_url": "https://yourapp.com/webhooks/ironbark",
"created_at": "2026-03-28T12:00:00+00:00",
"completed_at": null,
"items": []
}
Batch Job Status
Poll for batch job progress. Returns status, per-item scan_ids,
and any item-level errors. Safe to poll repeatedly — idempotent.
Job Status Values
| Status | Meaning |
|---|---|
pending | Job accepted, not yet started |
running | Items being processed |
completed | All items processed (some may have failed — check failed_items) |
Response
{
"job_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"status": "completed",
"total_items": 2,
"completed_items": 2,
"failed_items": 0,
"webhook_url": "https://yourapp.com/webhooks/ironbark",
"created_at": "2026-03-28T12:00:00+00:00",
"completed_at": "2026-03-28T12:00:03+00:00",
"items": [
{
"item_index": 0,
"entity_name": "John Smith",
"entity_type": "person",
"status": "completed",
"scan_id": "a1b2c3d4-...",
"error_message": null
},
{
"item_index": 1,
"entity_name": "Acme Pty Ltd",
"entity_type": "organisation",
"status": "completed",
"scan_id": "e5f6g7h8-...",
"error_message": null
}
]
}
Create Case
Create a compliance case from an existing scan. Cases are the audit record — they capture who reviewed a match, what decision was made, and when. The audit log is immutable and append-only.
| Field | Type | Description | |
|---|---|---|---|
scan_id | string | Required | UUID of an existing scan |
reviewer | string | Required | Reviewer identifier — email or name. Stored in audit log. |
Response (201 Created)
{
"case_id": "c9d8e7f6-...",
"scan_id": "3fa85f64-...",
"reviewer": "compliance@yourfirm.com.au",
"decision": "pending",
"decision_notes": null,
"scan_summary": {
"entity_name": "Anthony Albanese",
"entity_type": "person",
"risk_level": "low",
"risk_score": 12,
"match_count": 0,
"scanned_at": "2026-03-28T12:00:00+00:00"
},
"audit_log": [
{
"event_type": "case_created",
"actor": "compliance@yourfirm.com.au",
"event_data": {"reviewer": "compliance@yourfirm.com.au"},
"created_at": "2026-03-28T12:05:00+00:00"
}
],
"created_at": "2026-03-28T12:05:00+00:00",
"updated_at": "2026-03-28T12:05:00+00:00"
}
Get Case
Retrieve a compliance case with its full audit log.
Log Decision
Record a compliance decision on an existing case. Multiple decisions are allowed —
each appends a new event to the audit log. The decision field reflects
the most recent ruling.
| Field | Type | Description | |
|---|---|---|---|
decision | string | Required | "pending" | "true_match" | "false_positive" |
reviewer | string | Required | Reviewer identifier. Stored in audit log. |
notes | string | Optional | Free-text reviewer notes. Stored in audit log. |
Code Examples
case_id = "c9d8e7f6-..."
response = requests.patch(
f"https://api.ironbarkaml.com.au/v1/cases/{case_id}/decision",
headers={"Authorization": f"Bearer {token}"},
json={
"decision": "false_positive",
"reviewer": "compliance@yourfirm.com.au",
"notes": "Name match only, DOB and nationality do not match listed entity.",
},
)
await fetch(`https://api.ironbarkaml.com.au/v1/cases/${caseId}/decision`, {
method: "PATCH",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
decision: "false_positive",
reviewer: "compliance@yourfirm.com.au",
notes: "Name match only — DOB and nationality do not match.",
}),
});
uri = URI("https://api.ironbarkaml.com.au/v1/cases/#{case_id}/decision")
req = Net::HTTP::Patch.new(uri, {
'Authorization' => "Bearer #{token}",
'Content-Type' => 'application/json'
})
req.body = { decision: 'false_positive', reviewer: 'compliance@yourfirm.com.au' }.to_json
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("...v1/cases/" + caseId + "/decision"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.method("PATCH", HttpRequest.BodyPublishers.ofString(
"{\"decision\":\"false_positive\",\"reviewer\":\"compliance@yourfirm.com.au\"}"
))
.build();
curl -X PATCH https://api.ironbarkaml.com.au/v1/cases/CASE_ID/decision \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"decision": "false_positive",
"reviewer": "compliance@yourfirm.com.au",
"notes": "Name match only — DOB and nationality do not match."
}'
PDF Case Report
Generate a regulator-ready PDF report for a compliance case. The PDF includes: case details, scan summary, chronological audit log, and a SHA-256 document integrity hash in the footer.
Returns application/pdf with Content-Disposition: attachment; filename="ironbark-case-{id}.pdf".
Code Examples
case_id = "c9d8e7f6-..."
response = requests.get(
f"https://api.ironbarkaml.com.au/v1/cases/{case_id}/report",
headers={"Authorization": f"Bearer {token}"},
)
with open(f"ironbark-case-{case_id[:8]}.pdf", "wb") as f:
f.write(response.content)
const res = await fetch(
`https://api.ironbarkaml.com.au/v1/cases/${caseId}/report`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const buffer = await res.arrayBuffer();
fs.writeFileSync(`ironbark-case-${caseId.slice(0,8)}.pdf`, Buffer.from(buffer));
curl https://api.ironbarkaml.com.au/v1/cases/CASE_ID/report \
-H "Authorization: Bearer YOUR_TOKEN" \
-o ironbark-case.pdf
Webhook Events
Ironbark delivers webhook events to your HTTPS endpoint when async operations complete.
Supply webhook_url when submitting a batch job — no separate webhook registration required.
| Event | When | Phase |
|---|---|---|
batch.completed | All items in a batch job have been processed | Phase 2 |
scan.completed | Individual async scan finished | Phase 3 |
monitoring.alert | Monitored entity appears on a new list | Phase 3 |
credits.low_80 | Credit balance drops below 80% | Phase 3 |
credits.low_95 | Credit balance drops below 5% | Phase 3 |
api_key.expiring_soon | Client registration expires in <30 days | Phase 3 |
Example payload — batch.completed
{
"event": "batch.completed",
"timestamp": "2026-03-28T12:00:03.142857+00:00",
"data": {
"job_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"completed": 2,
"failed": 0
}
}
Signature Verification
Every webhook delivery includes an X-Ironbark-Signature header.
Verify this to confirm the request originated from Ironbark and was not tampered with.
Verification algorithm
- Read the raw request body as bytes
- Compute
HMAC-SHA256(body, your_webhook_secret) - Compare hex digest to the value after
sha256=in the header - Reject the request if they do not match
import hashlib, hmac
def verify_signature(body: bytes, secret: str, signature_header: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
provided = signature_header.removeprefix("sha256=")
return hmac.compare_digest(expected, provided)
const crypto = require("crypto");
function verifySignature(body, secret, signatureHeader) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
const provided = signatureHeader.replace("sha256=", "");
return crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(provided)
);
}
require 'openssl'
def verify_signature(body, secret, signature_header)
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, body)
provided = signature_header.sub('sha256=', '')
ActiveSupport::SecurityUtils.secure_compare(expected, provided)
end
Error Codes
All errors return JSON with a "detail" field describing the problem.
| Status | Meaning | Common causes |
|---|---|---|
400 | Bad Request | Invalid field value, wrong grant_type, missing required field |
401 | Unauthorized | Missing or expired Bearer token |
403 | Forbidden | Token valid but missing required scope |
404 | Not Found | Unknown scan_id, case_id, or job_id |
422 | Validation Error | Request body fails schema validation (FastAPI) |
429 | Too Many Requests | Rate limit exceeded — check Retry-After header |
500 | Internal Server Error | Scan execution failure — report to support |
503 | Service Unavailable | Database or Redis unavailable — check GET /health |
Error response shape
{
"detail": "Missing required scope: scans:write"
}
Validation error (422) shape
{
"detail": [
{
"loc": ["body", "entity_type"],
"msg": "value is not a valid enumeration member",
"type": "type_error.enum"
}
]
}
Ironbark API Reference · v1 · Built on solid ground.
Support: support@ironbark.ai