> For the complete documentation index, see [llms.txt](https://docs.fraudcheck.co.za/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fraudcheck.co.za/consumer-service/credit-and-financial-risk/credit-score.md).

# Credit Score

Credit Score returns a risk assessment for a South African consumer, combining credit bureau data with fraud indicators to produce a single classification (`ACCEPT` / `REVIEW` / `REJECT`) and a numeric score from 0–999. Use it as the quick decisioning input during onboarding, loan origination, and account opening.

The service returns:

* A **final score** (0–999) and risk category (`GREEN` / `AMBER` / `RED`)
* A **classification** suitable for automated decisioning
* **Fraud indicators** - SAFPS listing, deceased status, employer fraud, protective verification
* **Adverse information** - defaults, judgements, debt review

## When to use this

Use this service to:

* Make a single accept/review/reject decision during consumer onboarding
* Score loan applicants and account opening requests
* Combine credit and fraud risk into one decisioning step
* Replace multiple individual checks (SAFPS, defaults, judgements, deceased status) with one call

## How it works

The service is a **two-step call**. The first request submits the consumer's identity and returns a transaction ID along with enquiry identifiers. The second request uses those identifiers to fetch the full credit score report. Both calls are synchronous.

| Property              | Value                          |
| --------------------- | ------------------------------ |
| Response type         | `Synchronous` (two-step)       |
| Typical response time | 2–5s per call                  |
| Result retrieval      | Step 2 returns the full report |
| Consent required      | `Yes`                          |
| Region                | South Africa                   |

***

## Authentication

```http
Authorization: Bearer {your_access_token}
```

***

## Endpoints

```http
POST /prevet          # Step 1: submit consumer
POST /prevet/result   # Step 2: fetch full report
```

***

## Step 1 - Submit consumer

### Headers

| Header          | Required | Value              |
| --------------- | -------- | ------------------ |
| `Authorization` | Yes      | `Bearer {token}`   |
| `Content-Type`  | Yes      | `application/json` |

### Body parameters

| Field                              | Type    | Required | Description                                                        |
| ---------------------------------- | ------- | -------- | ------------------------------------------------------------------ |
| `IdentityNo`                       | string  | Yes      | 13-digit South African ID number                                   |
| `FirstName`                        | string  | Yes      | Consumer's first name                                              |
| `LastName`                         | string  | Yes      | Consumer's surname                                                 |
| `PrescribedPurpose`                | string  | Yes      | Purpose of the enquiry (e.g. `Account Opening`, `Loan Assessment`) |
| `ConsentObtainedByDataSubject`     | boolean | Yes      | Must be `true`. Confirms POPIA consent.                            |
| `SecondName`, `BirthDate`, `Sex`   | string  | No       | Additional identity fields                                         |
| `CellNo`, `EmailAddress`           | string  | No       | Contact details                                                    |
| `Employer`, `Occupation`, `Salary` | string  | No       | Employment details (improve fraud signals)                         |

### Example request

```json
{
  "IdentityNo": "8601015800086",
  "FirstName": "John",
  "LastName": "Smith",
  "PrescribedPurpose": "Account Opening",
  "ConsentObtainedByDataSubject": true
}
```

### Example response

```json
{
  "transaction_id": "TXN20240119ABC123XYZ",
  "identifier": "8601015800086",
  "first_name": "JOHN",
  "match": {
    "ListOfConsumers": [
      {
        "ConsumerID": "123456",
        "FirstName": "JOHN",
        "Surname": "SMITH",
        "IDNo": "8601015800086",
        "BirthDate": "1986-01-15",
        "EnquiryID": "ENQ12345",
        "EnquiryResultID": "RES67890"
      }
    ]
  }
}
```

Save the `transaction_id`, `EnquiryID`, and `EnquiryResultID` - you'll need them for step 2.

***

## Step 2 - Fetch full report

### Body parameters

| Field             | Type   | Required | Description                                     |
| ----------------- | ------ | -------- | ----------------------------------------------- |
| `transaction_id`  | string | Yes      | From step 1                                     |
| `EnquiryID`       | string | Yes      | From `match.ListOfConsumers[0].EnquiryID`       |
| `EnquiryResultID` | string | Yes      | From `match.ListOfConsumers[0].EnquiryResultID` |

### Example request

```json
{
  "transaction_id": "TXN20240119ABC123XYZ",
  "EnquiryID": "ENQ12345",
  "EnquiryResultID": "RES67890"
}
```

### Response - full report

The full report is returned under a top-level `Consumer` object with the following sub-sections:

| Section                                   | Description                                                              |
| ----------------------------------------- | ------------------------------------------------------------------------ |
| `Consumer.ConsumerDetail`                 | Demographics and identity                                                |
| `Consumer.ConsumerScoring`                | Final score, classification, and risk category                           |
| `Consumer.ConsumerFraudIndicatorsSummary` | Fraud signals (SAFPS, deceased, employer fraud, protective verification) |
| `Consumer.AdverseInfoSummary`             | Defaults, judgements, debt review                                        |

#### `ConsumerScoring` fields

| Field            | Type    | Description                                               |
| ---------------- | ------- | --------------------------------------------------------- |
| `FinalScore`     | integer | Risk score from `0` (lowest risk) to `999` (highest risk) |
| `RiskCategory`   | string  | `GREEN`, `AMBER`, or `RED`                                |
| `classification` | string  | `ACCEPT`, `REVIEW`, or `REJECT`                           |

#### `ConsumerFraudIndicatorsSummary` fields

| Field                         | `Y` means                                                     |
| ----------------------------- | ------------------------------------------------------------- |
| `SAFPSListingYN`              | Listed on the South African Fraud Prevention Service database |
| `HomeAffairsDeceasedStatus`   | Marked deceased on Home Affairs records                       |
| `EmployerFraudVerificationYN` | Employer details match a known fraud pattern                  |
| `ProtectiveVerificationYN`    | Subject has a protective registration on file                 |

#### `AdverseInfoSummary` fields

| Field                     | `Y` means                          |
| ------------------------- | ---------------------------------- |
| `XDSDefaultListingStatus` | Has payment default(s) on file     |
| `JudgementStatus`         | Has a legal judgement against them |
| `DebtReviewStatus`        | Currently under debt review        |

### Example response (abbreviated)

```json
{
  "Consumer": {
    "ConsumerDetail": {
      "FirstName": "JOHN",
      "Surname": "SMITH",
      "IDNo": "8601015800086",
      "BirthDate": "1986-01-15"
    },
    "ConsumerScoring": {
      "FinalScore": 245,
      "RiskCategory": "GREEN",
      "classification": "ACCEPT"
    },
    "ConsumerFraudIndicatorsSummary": {
      "SAFPSListingYN": "N",
      "HomeAffairsDeceasedStatus": "Alive",
      "EmployerFraudVerificationYN": "N",
      "ProtectiveVerificationYN": "N"
    },
    "AdverseInfoSummary": {
      "XDSDefaultListingStatus": "N",
      "JudgementStatus": "N",
      "DebtReviewStatus": "N"
    }
  }
}
```

***

## Decisioning at a glance

| `classification` | `RiskCategory` | Recommended action                                                |
| ---------------- | -------------- | ----------------------------------------------------------------- |
| `ACCEPT`         | `GREEN`        | Proceed with normal flow                                          |
| `REVIEW`         | `AMBER`        | Route to manual review; inspect fraud indicators and adverse info |
| `REJECT`         | `RED`          | Decline the application                                           |

A `REJECT` classification or any `Y` flag in `ConsumerFraudIndicatorsSummary` should be treated as a strong fraud or risk signal regardless of the numeric score.

***

## Errors

| HTTP | Code           | Meaning                                      | Action                                    |
| ---- | -------------- | -------------------------------------------- | ----------------------------------------- |
| 400  | `bad_request`  | Required field missing or consent not `true` | Provide all required fields               |
| 401  | `unauthorized` | Token missing or expired                     | Refresh your access token                 |
| 403  | `forbidden`    | Account lacks access to this service         | Contact your account manager              |
| 500  | `server_error` | Unexpected error                             | Contact support with the `transaction_id` |

***

## Code examples

{% tabs %}
{% tab title="cURL" %}

```bash
BASE_URL="https://consumer-service-api.fraudcheckonline.co.za/consumer-service"

# Step 1
curl -X POST "$BASE_URL/prevet" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "IdentityNo": "8601015800086",
    "FirstName": "John",
    "LastName": "Smith",
    "PrescribedPurpose": "Account Opening",
    "ConsentObtainedByDataSubject": true
  }'

# Step 2
curl -X POST "$BASE_URL/prevet/result" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "TXN20240119ABC123XYZ",
    "EnquiryID": "ENQ12345",
    "EnquiryResultID": "RES67890"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

BASE_URL = "https://consumer-service-api.fraudcheckonline.co.za/consumer-service"
headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json",
}

# Step 1 - submit consumer
step1 = requests.post(
    f"{BASE_URL}/prevet",
    headers=headers,
    json={
        "IdentityNo": "8601015800086",
        "FirstName": "John",
        "LastName": "Smith",
        "PrescribedPurpose": "Account Opening",
        "ConsentObtainedByDataSubject": True,
    },
).json()

transaction_id = step1["transaction_id"]
consumer = step1["match"]["ListOfConsumers"][0]

# Step 2 - fetch full report
report = requests.post(
    f"{BASE_URL}/prevet/result",
    headers=headers,
    json={
        "transaction_id": transaction_id,
        "EnquiryID": consumer["EnquiryID"],
        "EnquiryResultID": consumer["EnquiryResultID"],
    },
).json()

scoring = report["Consumer"]["ConsumerScoring"]
fraud = report["Consumer"]["ConsumerFraudIndicatorsSummary"]

print(f"Score: {scoring['FinalScore']}/999 ({scoring['RiskCategory']})")
print(f"Classification: {scoring['classification']}")

if fraud["SAFPSListingYN"] == "Y":
    print("⚠️  SAFPS listing on file")
if fraud["HomeAffairsDeceasedStatus"] != "Alive":
    print("⚠️  Deceased status flagged")
```

{% endtab %}

{% tab title="JavaScript (Node.js)" %}

```javascript
const BASE_URL = "https://consumer-service-api.fraudcheckonline.co.za/consumer-service";
const headers = {
  Authorization: `Bearer ${accessToken}`,
  "Content-Type": "application/json",
};

// Step 1
const step1 = await fetch(`${BASE_URL}/prevet`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    IdentityNo: "8601015800086",
    FirstName: "John",
    LastName: "Smith",
    PrescribedPurpose: "Account Opening",
    ConsentObtainedByDataSubject: true,
  }),
}).then(r => r.json());

const consumer = step1.match.ListOfConsumers[0];

// Step 2
const report = await fetch(`${BASE_URL}/prevet/result`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    transaction_id: step1.transaction_id,
    EnquiryID: consumer.EnquiryID,
    EnquiryResultID: consumer.EnquiryResultID,
  }),
}).then(r => r.json());

const { FinalScore, RiskCategory, classification } = report.Consumer.ConsumerScoring;
console.log(`${classification} - score ${FinalScore}/999 (${RiskCategory})`);
```

{% endtab %}
{% endtabs %}

***

## Compliance & consent

* Obtain explicit consent from the data subject before submitting a request.
* Set `ConsentObtainedByDataSubject` to `true` to confirm consent has been captured.
* Always supply a valid `PrescribedPurpose` matching the actual reason for the check.
* Retain proof of consent and the `transaction_id` for each enquiry in line with NCA and POPIA requirements.

***

## FAQ

<details>

<summary>Why is this a two-step call?</summary>

Step 1 matches the consumer and returns enquiry identifiers; step 2 uses those identifiers to retrieve the full scored report. Both calls happen synchronously and typically complete in a few seconds total.

</details>

<details>

<summary>How does the score relate to the classification?</summary>

`FinalScore` is a continuous 0–999 risk value. `RiskCategory` buckets it into `GREEN` / `AMBER` / `RED`, and `classification` translates that into an action (`ACCEPT` / `REVIEW` / `REJECT`). Use `classification` for automated decisioning and the underlying score and indicators when you need to explain the decision.

</details>

<details>

<summary>Higher score = higher or lower risk?</summary>

Higher = more risk. A score near `0` is the lowest-risk consumer; near `999` is the highest-risk.

</details>

<details>

<summary>What's the difference between this and the [Credit Check](credit-check.md) service?</summary>

Credit Check returns the raw bureau profile (accounts, balances, payment history). Credit Score adds fraud indicators on top and produces a single decision-ready classification. Use Credit Score for automated onboarding decisions; use Credit Check when you need the underlying account-level detail.

</details>

<details>

<summary>What client timeout should I configure?</summary>

Allow up to 30 seconds per call, 60 seconds total for both steps combined.

</details>

***

## Changelog

| Date       | Version | Change                                |
| ---------- | ------- | ------------------------------------- |
| 2026-04-11 | v1.0    | Initial release. Renamed from PreVet. |


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.fraudcheck.co.za/consumer-service/credit-and-financial-risk/credit-score.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
