> For the complete documentation index, see [llms.txt](https://developer.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://developer.fraudcheck.co.za/education/matric-verification.md).

# Matric Verification

Matric Verification confirms a South African consumer's secondary school qualification against official education records. Use it for employment screening, background checks, bursary eligibility, and detecting fraudulent education credentials.

Two variants are available depending on when the qualification was obtained:

| Variant       | Endpoint                                | Use for                                                                           |
| ------------- | --------------------------------------- | --------------------------------------------------------------------------------- |
| **Pre-1992**  | `/matric-verification/pre-1992/verify`  | Senior Certificate qualifications obtained before 1992                            |
| **Post-1992** | `/matric-verification/post-1992/verify` | National Senior Certificate and related qualifications obtained from 1992 onwards |

The Post-1992 variant additionally requires a `Qualification` field naming the specific certificate type.

The service is **asynchronous**: the initial request returns immediately with a `PENDING` status and a transaction ID. The final result is produced in the background and retrieved using that transaction ID.

## When to use this

Use this service to:

* Verify a matric qualification claim during pre-employment screening
* Check the validity of secondary education credentials
* Detect fraudulent education claims on CVs and applications
* Support compliance for roles with minimum education requirements

## How it works

Submit the consumer's name, ID number, and (for Post-1992) the qualification type in a single POST request to the appropriate variant endpoint. The service immediately accepts the request, creates a tracking transaction, and returns a `transaction_id` with `screening_result: "PENDING"`. The actual verification is processed in the background. Once complete, fetch the final result using the transaction endpoint.

| Property              | Value                                                    |
| --------------------- | -------------------------------------------------------- |
| Response type         | `Asynchronous`                                           |
| Typical response time | Immediate ack; final result usually within a few minutes |
| Result retrieval      | Poll `GET /transactions/{transaction_id}`                |
| Consent required      | `Yes`                                                    |
| Region                | South Africa                                             |

***

## Authentication

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

***

## Endpoints

{% tabs %}
{% tab title="Pre-1992" %}

```http
POST /matric-verification/pre-1992/verify
```

{% endtab %}

{% tab title="Post-1992" %}

```http
POST /matric-verification/post-1992/verify
```

{% endtab %}
{% endtabs %}

***

## Request

### 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                                                    |
| `ConsentObtainedByDataSubject` | boolean | Yes                | Must be `true`. Confirms POPIA consent.                               |
| `Qualification`                | string  | **Post-1992 only** | The qualification type. Must match one of the supported values below. |
| `SecondName`                   | string  | No                 | Middle name                                                           |
| `BirthDate`                    | string  | No                 | Date of birth (`YYYY-MM-DD`). Derived from `IdentityNo` if omitted.   |
| `ReferenceNo`                  | string  | No                 | Your internal reference, echoed in audit logs                         |

### Supported `Qualification` values (Post-1992)

* `Senior Certificate`
* `National Senior Certificate`
* `National Technical Certificate N1-N4`
* `National Certificate Vocational`
* `General Education and Training Certificate for Adults (GETC: ABET)`
* `General Education and Training Certificate for Adults (GETCA) - NQF 1`
* `National Senior Certificate for Adults (NASCA) - NQF 4`

Submitting any other value will return an HTTP 422 error listing the allowed values.

### Example request

{% tabs %}
{% tab title="Pre-1992" %}

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

{% endtab %}

{% tab title="Post-1992" %}

```json
{
  "IdentityNo": "9501015800086",
  "FirstName": "Jane",
  "LastName": "Doe",
  "Qualification": "National Senior Certificate",
  "ConsentObtainedByDataSubject": true
}
```

{% endtab %}
{% endtabs %}

***

## Response (initial acknowledgement)

The initial response confirms the request was accepted. The verification itself runs in the background.

### Response fields

| Field                  | Type   | Description                                                              |
| ---------------------- | ------ | ------------------------------------------------------------------------ |
| `transaction_id`       | string | Unique identifier for this request. Use it to retrieve the final result. |
| `screening_result`     | string | Initial status - always `PENDING` on the first response                  |
| `response_description` | string | Human-readable status message                                            |

### Example response - accepted

```json
{
  "transaction_id": "d41d8cd98f00b204e9800998ecf8427e",
  "screening_result": "PENDING",
  "response_description": "Request accepted and is being processed."
}
```

***

## Retrieving the final result

Once the verification has been processed in the background, fetch the final result using the transaction ID:

```http
GET /transactions/{transaction_id}
Authorization: Bearer {your_access_token}
```

The `screening_result` will transition from `PENDING` to one of:

| Result   | Meaning                                               |
| -------- | ----------------------------------------------------- |
| `ACCEPT` | The matric qualification was verified against records |
| `REVIEW` | A partial match was found that requires manual review |
| `REJECT` | The qualification could not be verified               |
| `FAILED` | The verification could not be completed               |

**Recommended polling:** every 5 seconds, up to 2 minutes. If the result is still `PENDING` after 2 minutes, switch to a longer interval with exponential backoff.

***

## Errors

| HTTP | Code            | Meaning                                                            | Action                                                   |
| ---- | --------------- | ------------------------------------------------------------------ | -------------------------------------------------------- |
| 401  | `unauthorized`  | Token missing or expired                                           | Refresh your access token                                |
| 403  | `forbidden`     | Account lacks access to this service                               | Contact your account manager                             |
| 422  | `invalid_input` | Required field missing, or `Qualification` not in the allowed list | See `details.allowed_values` or `details.missing_fields` |
| 500  | `server_error`  | Unexpected error                                                   | Contact support                                          |

***

## Code examples

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

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

# Pre-1992
curl -X POST "$BASE_URL/matric-verification/pre-1992/verify" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "IdentityNo": "8601015800086",
    "FirstName": "John",
    "LastName": "Smith",
    "ConsentObtainedByDataSubject": true
  }'

# Post-1992
curl -X POST "$BASE_URL/matric-verification/post-1992/verify" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "IdentityNo": "9501015800086",
    "FirstName": "Jane",
    "LastName": "Doe",
    "Qualification": "National Senior Certificate",
    "ConsentObtainedByDataSubject": true
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import time
import requests

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

# Submit a Post-1992 verification
response = requests.post(
    f"{BASE_URL}/matric-verification/post-1992/verify",
    headers=headers,
    json={
        "IdentityNo": "9501015800086",
        "FirstName": "Jane",
        "LastName": "Doe",
        "Qualification": "National Senior Certificate",
        "ConsentObtainedByDataSubject": True,
    },
)
transaction_id = response.json()["transaction_id"]
print(f"Submitted, transaction_id={transaction_id}")

# Poll for the final result
for _ in range(24):  # up to 2 minutes
    time.sleep(5)
    result = requests.get(f"{BASE_URL}/transactions/{transaction_id}", headers=headers).json()
    if result["screening_result"] != "PENDING":
        print(f"Final result: {result['screening_result']}")
        break
```

{% 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",
};

// Submit a Pre-1992 verification
const submit = await fetch(`${BASE_URL}/matric-verification/pre-1992/verify`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    IdentityNo: "8601015800086",
    FirstName: "John",
    LastName: "Smith",
    ConsentObtainedByDataSubject: true,
  }),
});
const { transaction_id } = await submit.json();

// Poll for the final result
for (let i = 0; i < 24; i++) {
  await new Promise(r => setTimeout(r, 5000));
  const res = await fetch(`${BASE_URL}/transactions/${transaction_id}`, { headers });
  const result = await res.json();
  if (result.screening_result !== "PENDING") {
    console.log(`Final result: ${result.screening_result}`);
    break;
  }
}
```

{% 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.
* Retain proof of consent and the `transaction_id` for each verification in line with POPIA requirements.

***

## FAQ

<details>

<summary>Which variant should I use?</summary>

Use **Pre-1992** for Senior Certificate qualifications obtained before 1992. Use **Post-1992** for National Senior Certificate and other modern qualifications obtained from 1992 onwards. If the consumer is unsure, their year of completion is a reliable guide.

</details>

<details>

<summary>Why does Post-1992 need a <code>Qualification</code> field?</summary>

Multiple qualification types fall under the Post-1992 framework (NSC, NCV, GETC, NASCA, etc.). The field tells the service which records to check.

</details>

<details>

<summary>Why is the result <code>PENDING</code> on the first response?</summary>

This service is asynchronous. The initial response confirms the request was accepted; the actual verification runs in the background and the final result becomes available shortly afterwards.

</details>

<details>

<summary>Do I need to provide <code>BirthDate</code>?</summary>

No. If omitted, it is derived from the South African ID number.

</details>

<details>

<summary>What does each final result mean?</summary>

`ACCEPT` = qualification verified. `REVIEW` = partial match needing manual review. `REJECT` = qualification could not be verified. `FAILED` = the verification could not complete; retry the request.

</details>

***

## Changelog

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