> For the complete documentation index, see [llms.txt](https://docs.uptiq.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.uptiq.ai/document-ai/cookbooks/fraud-and-control-checks.md).

# Reading fraud and control checks

**Goal.** Read the fraud-detection signals attached to a completed extraction, and use them to decide whether downstream processing should continue.

Fraud rules are configured in the portal. The API does not expose rule management — but a completed extraction record carries the **results**, which is what an automated gate actually needs.

### Before you start

* An API key, exported as `$DOCAI_API_KEY`.
* A completed asynchronous extraction and its `_id` — see [Extract asynchronously and poll](/document-ai/cookbooks/async-extraction-and-polling.md). The record retrieved by `GET /document-extractions/{id}` carries fraud results; the synchronous response does not.
* Fraud rules configured for the document type — see [Fraud Detection](/document-ai/guides-1/fraud-detection.md).

### Step 1 — Retrieve the extraction record

```bash
curl -s "https://api-docai-uat.uptiq.ai/document-extractions/$ID" \
  -H "X-Api-Key: $DOCAI_API_KEY" -o record.json

jq '.extraction.fraudResults' record.json
```

```json
{
  "fraudId": "d40f8b63-15ce-42a9-b806-9f37c2e6a851",
  "extractionId": "3f2a91c4-7b58-4e12-9d63-0a5e8c1b74df",
  "documentType": "BalanceSheet",
  "fraudStatus": "processing",
  "analysisStatus": "pending",
  "preflight": {
    "phase": "pre_ocr",
    "overallScore": 100.0,
    "genericRulesEvaluated": 15,
    "processingTimeMs": 25549,
    "categoryScores": {
      "compliance":         { "total": 6, "passed": 0, "failed": 0, "skipped": 6, "score": 0.0 },
      "social_engineering": { "total": 3, "passed": 1, "failed": 0, "skipped": 2, "score": 33.33 },
      "visual_forensic":    { "total": 9, "passed": 4, "failed": 0, "skipped": 5, "score": 44.44 }
    },
    "results": [ ],
    "errors": []
  }
}
```

### Step 2 — Wait for fraud analysis to finish

This is the part that catches people out.

{% hint style="danger" %}
**`Processed` on the extraction does not mean fraud analysis is done.** In our test run, the extraction reached `Processed` while `fraudStatus` still read `processing` and `analysisStatus` still read `pending`. Fraud analysis continues after extraction completes.

Reading `fraudResults` the moment the extraction goes terminal gives you a partial answer — and a partial answer that looks complete, because the object is fully populated with preflight data.
{% endhint %}

Check the fraud state separately from the extraction state:

```bash
jq -r '.extraction.fraudResults | "\(.fraudStatus)/\(.analysisStatus)"' record.json
```

Treat `fraudStatus` values other than a terminal one as "not yet decided", and re-poll the record. If your gate cannot wait, fail closed — hold the document for review rather than passing it on an incomplete signal.

### Step 3 — Read the category scores

Preflight checks are grouped into three categories:

| Category             | Looks for                                                                                  |
| -------------------- | ------------------------------------------------------------------------------------------ |
| `visual_forensic`    | Tampering evidence — inconsistent fonts, edited regions, missing print or export artifacts |
| `compliance`         | Whether the document carries what its type is required to carry                            |
| `social_engineering` | Patterns associated with documents constructed to deceive                                  |

Each reports `total`, `passed`, `failed`, `skipped` and a `score`.

{% hint style="warning" %}
**A low score is not evidence of fraud.** In the run above, `compliance` scored 0.0 with all six rules **skipped** — nothing failed. Rules skip when the document lacks what they need to evaluate, which is common for sparse or synthetic documents.

Gate on `failed`, not on `score`. A score depressed by skips means "could not assess", which is a different decision from "assessed and failed".
{% endhint %}

### Step 4 — Read individual rule results

```bash
jq '.extraction.fraudResults.preflight.results[] | {ruleId, status, category}' record.json
```

```json
{
  "ruleId": "bs-export-footprints-timestamps",
  "status": "SKIP",
  "category": "visual_forensic",
  "name": "Export Footprints: Printed/Export Timestamps Consistency",
  "details": {
    "explanation": "No 'Date Printed' or 'Time Exported' stamps are visible on page 1, so consistency cannot be evaluated.",
    "fieldsUsed": ["footer area", "header area", "all visible text"],
    "actualValues": { "visual_evidence": "No export or print timestamps present" },
    "expectedValues": {},
    "missingFields": [],
    "riskFactors": []
  }
}
```

`status` is `PASS`, `FAIL` or `SKIP`. `details.explanation` is written for a human — surface it in your review queue rather than paraphrasing it, and keep `riskFactors` where a reviewer can see them.

### Step 5 — Build the gate

```bash
FAILED=$(jq '[.extraction.fraudResults.preflight.results[]
              | select(.status == "FAIL")] | length' record.json)

if [ "$FAILED" -gt 0 ]; then
  echo "$FAILED fraud rule(s) failed — holding for review"
  jq -r '.extraction.fraudResults.preflight.results[]
         | select(.status == "FAIL")
         | "  \(.ruleId): \(.details.explanation)"' record.json
  exit 1
fi
```

A defensible policy has three outcomes rather than two: **pass** when nothing failed and coverage was adequate, **review** when rules failed or too many skipped to be meaningful, and **reject** only on the failures your risk team has agreed warrant it.

### What you cannot do through the API

| Not available                                      | Do it here                                                                                         |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Create or edit fraud rules                         | Document Types → Fraud Detection — see [Fraud Detection](/document-ai/guides-1/fraud-detection.md) |
| Enable or disable rules per document type          | Same screen                                                                                        |
| Export a certification report                      | Document Types screen                                                                              |
| Query fraud results independently of an extraction | Retrieve the extraction record                                                                     |

There is no fraud endpoint in the published API. Everything above reads results that ride along on the extraction record.

### Related pages

* [Fraud Detection](/document-ai/guides-1/fraud-detection.md) — configuring the rules these results come from.
* [Extract asynchronously and poll](/document-ai/cookbooks/async-extraction-and-polling.md) — obtaining the record in the first place.
* [Extraction API](/document-ai/developer-documentation/integration-guides/extraction.md) — `GET /document-extractions/{extraction_id}`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.uptiq.ai/document-ai/cookbooks/fraud-and-control-checks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
