Quickstart
Explain how rainbows form in a short sentence.
Submit contentSend only the messages you want scanned, including text or tool calls. Every supplied message is assessed.
Use an active project key with scan:write. Use the prompt endpoint for messages and tool calls, or the document endpoint for files. Zaun classifies the content and applies your project controls.
Sign up#
Where self-serve signup is open, create an account in the console with an email code,
Google or GitHub. Otherwise, join the waitlist or sign in with the email your
administrator invited. Signup creates your organization, a Default project with
protective controls, and a first key. The console then opens on Home, which shows the key
once and runs two scans on it: an ordinary prompt, and the published test string
ZAUN-TEST-VIOLATION-7f3a9c, which is always blocked.
Set up#
Load your real key from a secret store. Keep it out of source control and logs.
export ZAUN_BASE_URL='https://api.zaun.ai'
export ZAUN_API_KEY='zaun_REPLACE_WITH_YOUR_KEY'
Every scan response carries a scan_uuid. That one value fetches the result,
deletes it, and submits feedback.
Scan a prompt#
curl --silent --show-error --fail-with-body --max-time 50 \
"$ZAUN_BASE_URL/v1/scan/prompt" \
-H "Authorization: Bearer $ZAUN_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary '{"messages":[{"role":"user","content":"Explain least privilege."}]}'
There is no scan_type field. Classification assesses the submitted content and
combines findings across bounded windows for long inputs.
Every message in messages is scanned, including system, developer, user, assistant and tool messages. Only include messages you want scanned.
session_uuid groups related activity for later retrieval. Generate one UUID per conversation on your side and reuse it on every call; Zaun never assigns one. Messages the session has already scanned are not assessed again; each call is billed for its new tokens at the scan rate and for the session's earlier tokens, which the classifier reads back, at a tenth of it. See scan concepts.
Successful prompt and document scans return:
{
"scan_uuid": "3a723044-ed79-43c9-aa03-d74603503a49",
"completed_at": "2026-09-21T23:34:02.876876059Z",
"violation": true,
"action": "block",
"session_uuid": "54d5f93d-71eb-4ed0-bd0c-a8a01afeb38d",
"taxonomy": "mitre_atlas_tactic",
"technique": ["Execution", "Exfiltration"],
"usage": {"input_tokens": 5, "cached_input_tokens": 0, "output_tokens": 0},
"containment": "stop_turn"
}
violation identifies a detection independently of its configured action. If nothing
is detected, action is null and technique is empty. A detected violation uses the
strongest configured action: block, then redact, then alert, then no_action. Scans report
the action; your application enforces it. Completion endpoints enforce it themselves.
technique contains all detected labels, deduplicated and sorted. session_uuid
echoes the optional payload field or is null. usage is what the scan is billed:
the protected tokens your content adds, reported as usage.input_tokens, and with a
session_uuid the session's earlier tokens read back as usage.cached_input_tokens.
usage.output_tokens is always zero because scans charge input only, and failed
scans are never charged. containment is our recommendation for the turn, session or
tool, such as stop_turn or disable_tool; see scan concepts.
Technical failures return an error, never a compact successful response. Partial coverage cannot report no violation, but an established violation remains flagged. A completed classifier abstention means no violation was identified; it returns false/null/empty. Full evidence remains available through result retrieval. Completion response bodies and asynchronous document acknowledgements keep their existing format.
Scan output text and tool calls#
Use POST /v1/scan/prompt with assistant messages. Supply text, function tool calls,
or both; tool-only messages can use content: null. Function arguments are a JSON
object encoded as a string. This endpoint assesses content without executing tools.
{
"messages": [{
"role": "assistant",
"content": "Here is the requested summary.",
"tool_calls": [{
"id": "call_1",
"type": "function",
"function": {"name": "lookup", "arguments": "{\"query\":\"example\"}"}
}]
}],
"sample": true
}
Use a scan:write key. The response includes a generated scan_uuid. Text and tool calls share scan pricing and
organization limits.
Scan an image#
User messages can carry PNG or JPEG images as data URLs, up to four per request. Zaun reads their text and assesses it in place with the rest of the message, so a screenshot or photographed note carrying instructions is scanned like typed text.
{
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "Summarise this screenshot."},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}
]
}]
}
Each image costs $0.0075 on top of the protected tokens its text adds. Images without text are read and charged but add nothing to assess, and purely visual content is not assessed. See limits for sizes and billing rules.
Request flow#
- Authenticate the project key and validate the content and shared organization limits.
- Prepare submitted text, or extract document text.
- Classify the submitted content, using overlapping windows for long inputs.
- Combine classification and regex findings, then apply the project’s saved actions with the strongest action winning.
- Return the compact result. Your application enforces the action.
A Redact match adds redacted_prompt to prompt responses. Document scans
never return the full redacted document. See Project controls.
An optional payload sample: false hides this request's text from you, in the console and in session retrieval. Classification and billing are unchanged. Zaun still keeps a redacted copy for session context and campaign detection unless the project sets retain_activity to false.
Scan a document#
printf '%s' 'Explain least privilege.' > example.txt
curl --silent --show-error --fail-with-body --max-time 100 \
"$ZAUN_BASE_URL/v1/scan/document" \
-H "Authorization: Bearer $ZAUN_API_KEY" \
-F 'file=@example.txt'
Documents return the same compact response. Upload bytes rather than a URL. See
limits for supported formats, byte caps, and asynchronous submission.
This example waits for inline processing. For background processing, send
Prefer: respond-async with the same multipart body, then poll the returned
status_url. See document scans for
availability, complete request shape, acceptance response and retry behavior.
The direct extraction pipeline reads a PDF's own text layer, falling back to OCR, and uses native Office parsers, then classifies extracted text. Full evidence is available through result retrieval. Truncated extraction or failed coverage cannot establish benign. Upload bytes rather than a URL. The file limit is 10 MiB inside an 11 MiB multipart body; see limits for accepted formats and exact byte caps.
Read or delete a result#
Use the scan_uuid from the scan response, or the request_uuid from a completion
response, with a key carrying result:read or result:delete in the same project:
curl --silent --show-error --fail-with-body \
-H "Authorization: Bearer $ZAUN_API_KEY" \
"$ZAUN_BASE_URL/v1/result/REPLACE_WITH_SCAN_UUID"
DELETE on that URL tombstones the result. It does not erase usage accounting
or permit repeating a previously dispatched generation call.
Python#
import os
import requests
base = os.environ["ZAUN_BASE_URL"]
headers = {
"Authorization": f"Bearer {os.environ['ZAUN_API_KEY']}",
}
response = requests.post(
f"{base}/v1/scan/prompt",
headers=headers,
json={"messages": [{"role": "user", "content": "Explain least privilege."}]},
timeout=50,
)
response.raise_for_status()
result = response.json()
print(result["violation"], result["action"], result["technique"])
Dependency failures and unready references are API errors, distinct from an inconclusive assessment.
See scan feedback for assessment IDs and submitting a review without changing a verdict.
Scan responses identify the retained result by scan_uuid; it is also returned as the
X-Scan-Request-Id header. Completion responses use request_uuid for the persisted
generation. Each HTTP request starts a new operation.
Maintained with the API contract · Defaults may vary by deployment.