Developer Guides
·IdenticAPI

What Should an AI Security API Return?

AI security API response design — request IDs, verdicts, findings, risk, reasons, confidence, usage units, and consistent error models.

A production AI security API is only as useful as its response contract. Integrators need stable fields they can route on, log for audits, meter for billing, and correlate during incidents — without parsing natural-language messages or vendor-specific prose.

This guide documents what a well-designed security API should return, using real IdenticAPI response fields: request_id, verdict, findings, risk, and usage_units — plus supporting metadata your middleware should persist.

For endpoint specifics, see API Reference, Unified Guard, and Combine AI Security Guardrails.

Design goals

GoalWhy it matters
Machine-routablePolicy engines branch on enums, not prose
AuditableSecurity teams trace decisions months later
CorrelatableSupport links user reports to scanner results
MeterableFinance predicts cost; SRE detects abuse
VersionedDetector upgrades do not silently change semantics
Fail-distinctHTTP errors ≠ block verdicts

IdenticAPI responses follow these goals across individual detectors and Unified Guard.

Core fields (every successful scan)

request_id

Unique identifier for the API call. Store it alongside your application request ID.

"request_id": "req_abc123"

Use in middleware: log request_id + app trace_id; pass to support tooling; never substitute user content when reporting issues.

Error responses also include request_id (and X-Request-Id header). See Errors.

api

Product identifier for the endpoint that served the request.

"api": "prompt-injection-shield"

Unified Guard returns "api": "unified-guard". Helps when one log stream receives multiple detector types.

verdict (single-check endpoints)

Assessment result for standalone detectors:

Endpoint familyVerdict values
Prompt Injection, PII, Output Safetysafe, suspicious, unsafe
Agent Action Guardallow, review, block
"verdict": "unsafe",
"risk": "high",
"findings": [
  {
    "category": "instruction_override",
    "reason": "Instruction override pattern detected",
    "confidence": 0.92,
    "start": 0,
    "end": 42
  }
],
"reasons": ["Instruction override pattern detected"]

Policy mapping: your code translates verdict + risk + categories to allow, review, or block — the API does not execute product policy for you.

findings

Structured array — the primary integration surface for tuning and audit.

Typical finding fields:

FieldPurpose
categoryMachine enum (email, instruction_override, unsafe_html, …)
reasonHuman-readable explanation
confidenceOptional score for ranking or review priority
start / endOptional character offsets for redaction UI

Route policy on category, not only top-level verdict. Two suspicious responses with different findings[].category may deserve different actions.

PII example:

"findings": [
  { "category": "email", "reason": "Detected email (pii)", "confidence": 0.95, "start": 12, "end": 28 }
]

When redact: true on PII checks, use offsets or redacted_text to transform prompts before the LLM call.

risk

Severity hint: low, medium, high (and critical in some contexts per glossary).

Maps loosely to verdict — safe/allow → lower risk; unsafe/block → higher. Use risk + category together for review thresholds, not risk alone.

usage_units

Billable units consumed by this request.

"usage_units": 1
  • Single-detector calls: typically 1
  • Unified Guard: one unit per check (max four checks per request)
"usage_units": 2

Log usage_units for cost attribution per feature, tenant, or route. See Usage & Billing.

Supporting metadata fields

reasons

Flat list of human-readable strings — convenient for reviewer UIs and logs when you should not expose full finding objects to all systems.

confidence

Optional per-finding or aggregate signal. Do not treat as probability without vendor documentation. Useful for sorting review queues.

processing_time_ms

Server-side processing duration. Measure end-to-end latency in your region separately — network dominates many deployments.

detector_version

Engine version string (e.g. "1.0.0"). Annotate dashboards when block rates shift after upgrades.

redacted_text (PII path)

Returned when redact: true and findings exist. Substitute into LLM payload per policy.

Unified Guard: decision + checks[]

Orchestrated responses add an overall decision and per-check breakdown:

{
  "request_id": "req_abc123",
  "api": "unified-guard",
  "decision": "review",
  "checks": [
    {
      "check": "prompt_injection",
      "verdict": "allow",
      "risk": "low",
      "findings": [],
      "reasons": ["No injection patterns detected"]
    },
    {
      "check": "pii_secrets",
      "verdict": "review",
      "risk": "medium",
      "findings": [{ "category": "email", "reason": "Detected email (pii)" }],
      "reasons": ["Detected email (pii)"]
    }
  ],
  "usage_units": 2,
  "processing_time_ms": 45,
  "detector_version": "1.0.0"
}

Decision priority: block > review > allow.

Persist the full checks[] array — not only decision — so incident response knows which detector fired.

Error response design

Security APIs must distinguish:

SituationHTTPBody signalApp behavior
Content flagged200verdict: unsafe or decision: blockPolicy block
Invalid input400error.code, error.messageFix client
Auth failure401error objectRotate key
Rate limit429error + retry guidanceBackoff
Server error5xxrequest_id in errorFail-open or fail-closed per policy

Never map HTTP 500 to "allow because no verdict." Explicitly implement fail-open vs fail-closed.

Example error shape:

{
  "error": {
    "code": "invalid_request",
    "message": "text exceeds maximum length"
  },
  "request_id": "req_abc123"
}

Middleware integration pattern

type GuardResult = {
  requestId: string;
  verdict: "safe" | "suspicious" | "unsafe";
  risk: string;
  findings: Array<{ category: string; reason: string }>;
  usageUnits: number;
};

async function screenInput(text: string): Promise<GuardResult> {
  const res = await fetch("https://www.identicapi.com/api/v1/security/prompt-injection", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.IDENTICAPI_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ text, source: "chat_input" })
  });

  if (!res.ok) {
    // Distinct from unsafe verdict — apply outage policy
    throw new ScannerUnavailableError(await res.json());
  }

  const data = await res.json();
  return {
    requestId: data.request_id,
    verdict: data.verdict,
    risk: data.risk,
    findings: data.findings,
    usageUnits: data.usage_units
  };
}

Log requestId, verdict, risk, finding categories, and usageUnits — not necessarily full text.

Schema stability and CI

Assert in tests:

  • Required keys exist (request_id, verdict or decision, findings, risk, usage_units)
  • Verdict enums are members of documented sets
  • findings[].category is a string
  • Error responses include request_id

Pin detector_version in regression notes when baselines change.

What not to put in responses

AvoidPrefer
Only a numeric "risk score"verdict + findings[].category
Natural-language-only resultsStructured findings + reasons
Echoing full input in errorsrequest_id + error code
Implicit "guarantee" languageDocument verdicts as risk signals

Verdicts are risk signals, not legal guarantees or compliance certifications.

Field checklist for vendor evaluation

When comparing guardrail APIs, require:

  • request_id on success and error
  • Structured findings with categories
  • Documented verdict enum per check type
  • Explicit usage_units or equivalent metering
  • processing_time_ms or latency header
  • Version field for detector changes
  • Distinct HTTP errors vs block verdicts
  • Multi-check breakdown (or honest single-check only)

See AI Guardrails API for evaluation criteria.

Summary

Production integrations center on five fields:

  1. request_id — correlation and support
  2. verdict / decision — routing
  3. findings — category-level policy and audit
  4. risk — severity hints for review queues
  5. usage_units — cost and abuse monitoring

IdenticAPI implements this contract across Prompt Injection Shield, PII & Secrets Detection, AI Output Safety, Agent Action Guard, and Unified Guard. Your middleware owns policy; the API owns structured risk signals.

Frequently asked questions

What fields should every AI security API response include?

At minimum: request_id for correlation, verdict or decision for routing, findings with categories for audit and tuning, risk for severity hints, and usage_units for metering. IdenticAPI also returns reasons, processing_time_ms, and detector_version.

What is the difference between verdict and decision in IdenticAPI?

Single-detector endpoints return verdict (safe/suspicious/unsafe or allow/review/block). Unified Guard returns an overall decision plus a checks array with per-check verdicts. Decision priority is block > review > allow.

How should applications use the findings array?

Route policy on findings[].category — not only top-level verdict. Two suspicious responses with different categories may deserve different actions. Log categories and request_id; avoid logging raw secrets in production.

How are usage_units calculated?

Single-detector calls typically consume one usage unit. Unified Guard charges one unit per check in the request, up to four checks maximum. The usage_units field in each response reflects units consumed for that call.

How should HTTP errors differ from block verdicts?

A 200 response with verdict unsafe or decision block is a policy signal. HTTP 4xx/5xx are transport or validation failures. Applications must implement explicit fail-open or fail-closed behavior on errors — never treat a 500 as implicit allow.

Related reading