> ## Documentation Index
> Fetch the complete documentation index at: https://docs.starfort.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Response format

> The Starfort Guard API response schema: top-level action, per-part input_results, and detected_items for PII and Topic (Starfort v1.4 docs)

A successful call returns **HTTP 200** with a top-level `action` and a per-content-part breakdown in `input_results`. Starfort returns the Guardian's response body **verbatim** — no wrapper, no field reshaping.

## The action model

The action set depends on the policy type:

* **PII** policies return `PASS` / `MASK` / `BLOCK`.
* **Topic** policies are **2-state**: they return `PASS` or `BLOCK` (a topic classified `unsafe` blocks; everything else passes).

The root `action` is the **highest severity** across everything detected: `BLOCK` > `MASK` > `PASS`. See [Actions](/en/v1.4/concepts/actions-pass-mask-block).

## Top-level

| Field           | Type   | Notes                                                                      |
| --------------- | ------ | -------------------------------------------------------------------------- |
| `action`        | string | `PASS` \| `MASK` \| `BLOCK` — the **highest severity** across all results. |
| `input_results` | array  | One entry per inspected content part. Empty when nothing was inspected.    |

Each `input_results[]` entry:

| Field                    | Notes                                                                                                                                                                                                                                                                                                                                                                   |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `index`                  | Position of the content part in `messages[].content`.                                                                                                                                                                                                                                                                                                                   |
| `type`                   | `text`, `image`, `audio`, `video`, `document`, `archive`.                                                                                                                                                                                                                                                                                                               |
| `identifier`             | File name for file parts; otherwise `null`.                                                                                                                                                                                                                                                                                                                             |
| `action`                 | This part's action.                                                                                                                                                                                                                                                                                                                                                     |
| `processed_content`      | The **processed content** — what Guardian parsed, normalized (OCR'd or decoded where needed), and re-encoded. Always populated on the verdicts that deliver content onward (`PASS` and `MASK`) — a string for text parts, a base64 string for file parts. `null` on `BLOCK`, and for inputs no processed content could be built from (unsupported, processing failure). |
| `processed_content_type` | The content type of `processed_content` — `text` for text, a MIME type for files. `null` when `processed_content` is `null`.                                                                                                                                                                                                                                            |
| `results`                | Per-policy results (see below).                                                                                                                                                                                                                                                                                                                                         |

## MASK example (PII)

```json theme={"dark"}
{
  "action": "MASK",
  "input_results": [{
    "index": 0, "type": "text", "identifier": null, "action": "MASK",
    "processed_content": "My number is [PHONE_NUMBER_1] and my email is [EMAIL_1].",
    "processed_content_type": "text",
    "results": [{
      "policy_name": "PII Masking Policy", "policy_type": "PII", "action": "MASK",
      "detected_items": [
        { "rule_type": "regex", "rule_id": 15, "rule_name": "phone_number:_korea_mobile_all_separators",
          "action": "MASK", "confidence": 1, "mask_word": "PHONE_NUMBER_1",
          "matched_text": "010-2543-2513", "alert_message": "Mobile phone number detected" },
        { "rule_type": "regex", "rule_id": 18, "rule_name": "email:_email_address",
          "action": "MASK", "confidence": 1, "mask_word": "EMAIL_1",
          "matched_text": "jane@acme.co.kr", "alert_message": "Email address detected" }
      ]
    }]
  }]
}
```

**Masking token format:** `[<MASK_WORD>_<n>]`, numbered per occurrence (`[PHONE_NUMBER_1]`, `[PHONE_NUMBER_2]`, …).

## Processed-content egress — what goes out is always `processed_content`

Starting with v1.4, the content that leaves for an external AI service is never the caller's original — it's the **processed content** (`processed_content`) that Guardian actually inspected and rebuilt:

* **PASS** — the processed content is delivered. Even when nothing needed masking and the content reads the same as the original, what's delivered is Guardian's rebuilt version.
* **MASK** — the masked processed content is delivered.
* **BLOCK** — nothing is delivered (`processed_content` is `null`).
* **Inputs no processed content could be built from** (unsupported files, parse or decode failures) — Guardian couldn't verify the contents, so the field is `null`, and the original must not be sent in its place (fail-closed).

For inputs that go through OCR, decoding, or parsing — images, documents, audio — there's no guarantee the conversion captured everything in the original. Delivering only the processed content confines egress to the representation Guardian actually verified, closing the path where unverified content rides out inside the original.

<Note>
  **What changed from v1.3** — through v1.3, `processed_content` was populated only on `MASK`, and `PASS` meant the caller's original went out as-is (the field was `null`). From v1.4 on, `PASS` populates the processed content too, and delivering it instead of the original is the contract.
</Note>

## BLOCK example (Topic)

```json theme={"dark"}
{
  "action": "BLOCK",
  "input_results": [{
    "index": 0, "type": "text", "identifier": null, "action": "BLOCK",
    "processed_content": null, "processed_content_type": null,
    "results": [{
      "policy_name": "Topic Policy", "policy_type": "TOPIC", "action": "BLOCK",
      "detected_items": [
        { "rule_id": "WPN", "rule_name": "Weapons", "action": "BLOCK",
          "confidence": 1, "classification": "unsafe", "alert_message": "…" }
      ]
    }]
  }]
}
```

## `detected_items` — PII vs. Topic

The fields differ by policy type:

| Field                                   | PII                           | Topic                                 |
| --------------------------------------- | ----------------------------- | ------------------------------------- |
| `rule_type`                             | `ner` \| `regex` \| `keyword` | —                                     |
| `rule_id`                               | integer                       | string topic code (e.g. `WPN`)        |
| `rule_name`                             | rule name                     | topic title                           |
| `classification`                        | —                             | `safe` (→ PASS) \| `unsafe` (→ BLOCK) |
| `mask_word`                             | present (MASK)                | —                                     |
| `matched_text`                          | the matched span              | —                                     |
| `action`, `confidence`, `alert_message` | yes                           | yes                                   |

<Note>
  Read the top-level `action` first. On `PASS` and `MASK`, send `processed_content` onward instead of the original (see the processed-content egress rule above). On `BLOCK`, do not call your model. See [Actions](/en/v1.4/concepts/actions-pass-mask-block).
</Note>

## `PASS` always means "analyzed, nothing detected"

A `PASS` with empty `results` is never ambiguous: it means the Guardian **completed analysis and found nothing** — not that it failed to analyze. A request the Guardian cannot analyze returns an **HTTP error** instead of a degraded 200 (Guardian fail-closed), so a failure can never be mistaken for a clean result. See [Errors & states](/en/v1.4/api/errors).
