Citadel API v1
The API is the one the CLI and MCP server use. It lets you integrate Citadel into your own tools: upload a ZIP archive, start the analysis and fetch the result as JSON.
Authentication
Create a free account at citadelscan.com, then an API key in Console › CLI & IDE. A key acts on your behalf in one workspace; it is shown once and can be revoked at any time.
curl https://citadelscan.com/api/v1/me \
-H "Authorization: Bearer cit_..."| Rule | Value |
|---|---|
| Base URL | https://citadelscan.com/api/v1 |
| Format | JSON, UTF-8 |
| Rate limit | 300 requests per 10 minutes per key |
| Analyses per hour | Free 3, Builder 10, Pro 30, Agency 60 (on top of the monthly quota: Free 10, Builder 60) |
| Concurrent analyses | Free and Builder 1, Pro 3, Agency 5; beyond that, a 429 response with a clear message |
| Errors | HTTP 4xx status and body { "error": "readable message" } |
| Language | Flaw texts in the account’s language |
GET /me
Checks the key: account, workspace, plan and role.
{
"user": { "name": "Awa Mensah", "email": "awa@example.com" },
"workspace": { "name": "Studio Awa", "plan": "pro" },
"role": "owner",
"lang": "fr"
}POST /uploads
Prepares a ZIP archive upload (50 MB at most). The project is found by name, or created: consent must be true to attest you may analyse this code.
{ "project": "my-app", "consent": true, "size": 482133 }{
"projectId": "2b91…",
"url": "https://…/uploads",
"fields": { "key": "archives/…/….zip", "Content-Type": "application/zip", "Policy": "…", "X-Amz-Signature": "…" },
"key": "archives/…/….zip"
}Then send the archive as multipart/form-data to url, with every field from fields and then the file in the file field. The URL is valid for 10 minutes.
curl -X POST "$URL" \
-F key=… -F Content-Type=application/zip -F Policy=… -F X-Amz-Signature=… \
-F file=@app.zipPOST /scans
Starts the analysis of the uploaded archive. sha256 is the hex digest of the ZIP file: the same archive sent twice only creates one analysis (duplicate: true).
{ "projectId": "2b91…", "key": "archives/…/….zip", "sha256": "9f86d08…" }{ "scanId": "6f0c…", "duplicate": false }GET /scans/{id}
Status and result of an analysis. Poll about every 3 seconds until a final status: succeeded, partial (one engine failed), failed or cancelled. grade, counts, coverage and findings are only present after a successful analysis; only open flaws are listed, most severe first.
{
"id": "6f0c…",
"status": "succeeded",
"project": { "id": "2b91…", "name": "my-app" },
"reportUrl": "https://citadelscan.com/app/projects/2b91…/scans/6f0c…",
"steps": [
{ "key": "inspect", "label": "Sorting and checking: only useful files are kept", "state": "done", "detail": "412 files kept · 1 380 set aside" },
{ "key": "code", "label": "Reading the code: OWASP flaws", "state": "done", "detail": "2 issues" }
],
"error": null,
"grade": "C",
"counts": { "critical": 0, "high": 1, "medium": 1, "low": 0, "info": 0 },
"coverage": null,
"findings": [
{
"id": "a41e…",
"severity": "high",
"ruleId": "citadel.supabase.rls-disabled",
"category": "A01:2021",
"cwe": ["CWE-284"],
"title": "Row Level Security disabled on a table",
"description": "…",
"impact": "…",
"recommendation": "Enable RLS on the table and add one policy per role.",
"file": "supabase/migrations/0001_init.sql",
"line": 9,
"evidence": "alter table public.orders disable row level security;"
}
]
}coverage is not null when part of the code is in a language Citadel doesn’t read yet: the grade then reflects only part of the risks.
The free plan includes 10 analyses a month, CLI and MCP included, no card needed.
Nobody reads your code: it is analysed automatically in an isolated environment, then deleted. Code privacy