Async Deep Scans
Use async scans, polling, and webhooks for deep image and PDF review.
Goal
Run deeper scans without blocking a user request.
Async scans are for image and PDF workflows where depth matters more than immediate completion.
You can request async processing explicitly. Mighty may also automatically offload an eligible PDF when completing it inside the synchronous budget would risk a timeout. Every PDF client must therefore handle 202 Accepted, even when it did not set async=true.
Explicit Async Requirements
async=truemode=comprehensivecontent_type=imageorcontent_type=pdf- Optional
webhook_url
Automatic PDF offload does not require these request fields. It uses the same 202 and polling contract when Mighty needs to protect a bounded synchronous request.
Architecture
- Submit the image or PDF with
async=true. - On
202 Accepted, store the returnedscan_idandLocationheader. - Show a pending review state to the user or workflow.
- Wait at least the
Retry-Afterinterval, then receive the webhook or pollLocation. - Route the final result.
Submit An Async Scan
curl -X POST https://gateway.trymighty.ai/v1/scan \
-H "Authorization: Bearer $MIGHTY_API_KEY" \
-F "file=@./claim-packet.pdf" \
-F "content_type=pdf" \
-F "scan_phase=input" \
-F "mode=comprehensive" \
-F "focus=all" \
-F "async=true" \
-F "webhook_url=https://example.com/api/mighty/webhook"Poll For Completion
curl https://gateway.trymighty.ai/v1/scan/c178225b-1ee2-4c60-bab3-41f1ad32d532 \
-H "Authorization: Bearer $MIGHTY_API_KEY"preliminary: true on the initial response means the scan is still running — do not treat its action or threats as final. Each item in threats is an object with category, confidence, an optional evidence excerpt, and a human-readable reason.
Webhook Handler Shape
Webhook delivery is at least once, not exactly once. A receiver can commit a
request and lose its HTTP response, so Mighty may send the same event again.
Every retry carries the same X-Citadel-Event-Id and Idempotency-Key; persist
that value with a unique constraint before applying downstream effects. The
X-Citadel-Scan-Id header remains the scan correlation ID.
export async function POST(request: Request) {
const scan = await request.json();
await saveMightyScanResult({
scanId: scan.scan_id,
scanGroupId: scan.scan_group_id,
action: scan.action,
riskScore: scan.risk_score,
status: scan.scan_status,
threats: scan.threats ?? [],
});
await routeFinalScanResult(scan);
return Response.json({ ok: true });
}Validate webhook authenticity according to your deployment policy. At minimum, use HTTPS, strict routing, request logs, replay protection, and a secret value in your own webhook path or headers when available.
Routing Logic
export function routeAsyncStatus(scan: { scan_status?: string; action?: string }) {
if (scan.scan_status === "pending") return "keep_pending";
if (scan.scan_status === "failed") return "manual_review";
if (scan.action === "ALLOW") return "continue";
if (scan.action === "REVIEW") return "manual_review";
if (scan.action === "WARN") return "manual_review";
return "stop";
}Common Mistakes
- Setting
async=truewithmode=secure. Async requiresmode=comprehensive. - Using async for text. Async deep scan is for image and PDF.
- Letting the workflow continue before final routing.
- Treating a preliminary response as the final answer.
Production Checklist
- Store pending state with
scan_id. - Poll the returned
Locationand honorRetry-Afterbefore every retry. - Make webhook handling idempotent.
- Deduplicate webhook retries by
X-Citadel-Event-IdorIdempotency-Key; do not assume one delivery. - Re-route if the final result differs from the preliminary route.
- Add monitoring for stuck pending scans.
- Use manual review as the safe fallback for failed deep scans.
- Treat
429as capacity backpressure and503as an unavailable job store; neither is an accepted scan.
Ready to scan real traffic?
Create an API key, keep it on your server, then wire Mighty into the workflow that handles untrusted material.
AI-Agent Prompt
Paste this into Cursor, Codex, Claude Code, or Windsurf.
Add Mighty async deep scans for high-risk PDF or image workflows.
Requirements:
- Submit file scans with async=true and mode=comprehensive.
- Only use async for content_type=image or content_type=pdf.
- Store scan_id, scan_group_id, preliminary, scan_status, and action.
- Add a pending state in the workflow.
- Implement GET /v1/scan/{scan_id} polling with backoff.
- Implement webhook receiving if the app has a public HTTPS endpoint.
- Make webhook updates idempotent.
- Route complete ALLOW, WARN, BLOCK.
- Route failed or stuck pending scans to manual review.
Acceptance criteria:
- Tests cover pending, complete, failed, webhook duplicate, and polling retry.
- The workflow does not treat preliminary as final.
- Logs include scan_id and request_id.