> 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/identity/driver-licence-verification.md).

# Driver's Licence Verification

Verifies a **South African-issued** driver's licence  and Professional Driving Permit against the issuing authority's records. The licence holder does not need to be a South African citizen, a foreign national holding a valid **SA-issued licence** can be verified too, but the licence itself must have been issued in South Africa. \
\
This verification is **asynchronous.** the initial call only submits the check; the result becomes available in 24 - 48 Hours

## When to use this

Use this service to:

* Confirm that a submitted driver's licence number, type, and holder identity are valid and on record
* Retrieve licence class, restrictions, issue date, and expiry date for a verified licence
* Verifying a Professional Driving Permit

## How it works

Submit the licence holder's Identity number, name, licence type, and licence number in a single POST request. The request is validated and forwarded for verification; the transaction is created immediately with a `PENDING` result while it's processed.

Poll `GET /driver-licence/status/{transaction_id}` until `results_available` is `true`, then call `GET /driver-licence/results/{transaction_id}` to retrieve the verified licence details.

| Property              | Value                                                                                              |
| --------------------- | -------------------------------------------------------------------------------------------------- |
| Response type         | `Asynchronous`                                                                                     |
| Typical response time | Submission is immediate; result availability in 24 - 48 Hours                                      |
| Result retrieval      | `GET /driver-licence/status/{transaction_id}`, then `GET /driver-licence/results/{transaction_id}` |
| Consent required      | `Yes`                                                                                              |
| Region                | South Africa (SA-issued licences only, regardless of the holder's nationality)                     |

***

## Authentication

All requests require a Bearer token in the `Authorization` header.

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

***

## Endpoints

```http
POST /driver-licence/verify
GET  /driver-licence/status/{transaction_id}
GET  /driver-licence/results/{transaction_id}
```

## 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. If the value does not pass SA ID validation, it is treated as a foreign/passport document and `BirthDate` becomes required.                          |
| `FirstName`                    | string  | Yes         | Licence holder's first name                                                                                                                                                            |
| `LastName`                     | string  | Yes         | Licence holder's surname                                                                                                                                                               |
| `LicenseType`                  | string  | Yes         | One of: `card`, `temporary`, `learners`                                                                                                                                                |
| `LicenseNumber`                | string  | Yes         | The licence number to verify                                                                                                                                                           |
| `ConsentObtainedByDataSubject` | boolean | Yes         | Confirms POPIA consent. Requests without confirmed consent are rejected.                                                                                                               |
| `BirthDate`                    | string  | Conditional | Required only when `IdentityNo` fails SA ID validation (e.g. a passport number)                                                                                                        |
| `CellNo`                       | string  | No          | Licence holder's contact number                                                                                                                                                        |
| `CountryCode`                  | string  | No          | Numeric key for the licence holder's own country/nationality (not the licence's country of issue, which is always South Africa for this service). Defaults to South Africa if omitted. |
| `CostCenter`                   | integer | No          | Client-side cost centre reference, recorded against this transaction for billing/audit purposes                                                                                        |

### Example request

```json
{
  "IdentityNo": "*************",
  "FirstName": "John",
  "LastName": "Smith",
  "LicenseType": "card",
  "LicenseNumber": "**********",
  "CellNo": "0821234567",
  "ConsentObtainedByDataSubject": true
}
```

***

## Response

### POST /driver-licence/verify

Submitting a request never returns a final verification outcome — it confirms the check was accepted for processing.

| Field              | Type    | Description                                         |
| ------------------ | ------- | --------------------------------------------------- |
| `success`          | boolean | `true` if the submission was accepted               |
| `message`          | string  | Human-readable confirmation                         |
| `transaction_id`   | string  | Unique identifier — use this to poll status/results |
| `screening_result` | string  | Always `PENDING` at submission time                 |

```json
{
  "success": true,
  "message": "Driver licence verification submitted successfully.",
  "transaction_id": "d41d8cd98f00b204e9800998ecf8427e",
  "screening_result": "PENDING"
}
```

### GET /driver-licence/status/{transaction\_id}

Poll this endpoint to check whether a result is ready yet.

| Field               | Type    | Description                                                                             |
| ------------------- | ------- | --------------------------------------------------------------------------------------- |
| `transaction_id`    | string  | The transaction being checked                                                           |
| `screening_result`  | string  | `null` while pending; otherwise the current screening result                            |
| `is_complete`       | boolean | `true` once verification processing has finished                                        |
| `results_available` | boolean | Same as `is_complete` — call `GET /driver-licence/results/{transaction_id}` once `true` |
| `message`           | string  | `"Check is still being processed."` or `"Check is complete. Results are available."`    |

### GET /driver-licence/results/{transaction\_id}

Returns the full verified licence record once processing is complete. Also returns whatever partial data exists if called before completion.

| Field                        | Type    | Description                                              |
| ---------------------------- | ------- | -------------------------------------------------------- |
| `success`                    | boolean | `true` if the transaction was found                      |
| `transaction_id`             | string  | The transaction identifier                               |
| `screening_result`           | string  | Current screening result                                 |
| `received_datetime`          | string  | When the original request was received                   |
| `data.first_name`            | string  | Submitted first name                                     |
| `data.last_name`             | string  | Submitted surname                                        |
| `data.identity_no`           | string  | Submitted ID number                                      |
| `data.license_type`          | string  | Submitted licence type                                   |
| `data.license_number`        | string  | Submitted licence number                                 |
| `data.normalized_validity`   | string  | `VALID`, `INVALID`, or `UNKNOWN`                         |
| `data.parsed_license_class`  | string  | Licence class/code, parsed from the supplier response    |
| `data.parsed_issued_date`    | string  | Licence issue date, parsed from the supplier response    |
| `data.parsed_expiry_date`    | string  | Licence expiry date, parsed from the supplier response   |
| `data.parsed_license_number` | string  | Licence number, parsed from the supplier response        |
| `data.parsed_license_type`   | string  | Licence type/category, parsed from the supplier response |
| `data.license_restrictions`  | string  | Any restrictions recorded against the licence            |
| `data.comments`              | string  | Free-text comments recorded by the back-office verifier  |

### Example: completed result

```json
{
  "success": true,
  "message": "Driver licence transaction fetched successfully",
  "transaction_id": "d41d8cd98f00b204e9800998ecf8427e",
  "screening_result": "ACCEPT",
  "received_datetime": "2026-09-01T09:12:03",
  "data": {
    "product_name": "Drivers License Verification South Africa",
    "first_name": "John",
    "last_name": "Smith",
    "identity_no": "*************",
    "license_type": "card",
    "license_number": "**********",
    "comments": "Verified against eNaTIS",
    "license_restrictions": "None",
    "parsed_license_class": "EB",
    "parsed_issued_date": "2019-03-14",
    "parsed_expiry_date": "2029-03-14",
    "parsed_license_number": "**********",
    "parsed_license_type": "Card",
    "normalized_validity": "VALID"
  }
}
```

***

## Errors

| HTTP | Code           | Meaning                                                                                             | Action                                                              |
| ---- | -------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| 422  | invalid\_input | `LicenseType` is not one of `card`/`temporary`/`learners`, or `CountryCode` is not a recognised key | Correct the field and resubmit                                      |
| 422  | missing\_field | `BirthDate` missing when `IdentityNo` is not a valid SA ID number                                   | Supply `BirthDate` for passport/foreign document submissions        |
| 401  | unauthorized   | Token expired or invalid                                                                            | Refresh the access token                                            |
| 403  | forbidden      | Transaction exists but belongs to a different account                                               | Confirm you're querying with the account that submitted the request |
| 404  | not\_found     | Transaction does not exist                                                                          | Check the `transaction_id`                                          |

***

## Code examples

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

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

# 1. Submit
curl -X POST "$BASE_URL/driver-licence/verify" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "IdentityNo": "*************",
    "FirstName": "John",
    "LastName": "Smith",
    "LicenseType": "card",
    "LicenseNumber": "**********",
    "ConsentObtainedByDataSubject": true
  }'

# 2. Poll status
curl "$BASE_URL/driver-licence/status/$TRANSACTION_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# 3. Fetch result once results_available is true
curl "$BASE_URL/driver-licence/results/$TRANSACTION_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

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

submit = requests.post(
    f"{BASE_URL}/driver-licence/verify",
    headers=headers,
    json={
        "IdentityNo": "*************",
        "FirstName": "John",
        "LastName": "Smith",
        "LicenseType": "card",
        "LicenseNumber": "**********",
        "ConsentObtainedByDataSubject": True,
    },
)
transaction_id = submit.json()["transaction_id"]

status = requests.get(f"{BASE_URL}/driver-licence/status/{transaction_id}", headers=headers)
if status.json()["results_available"]:
    result = requests.get(f"{BASE_URL}/driver-licence/results/{transaction_id}", headers=headers)
    print(result.json())
```

{% endtab %}
{% endtabs %}

***

## Compliance & consent

Explicit consent must be obtained from the licence holder before submitting a verification request.

`ConsentObtainedByDataSubject` must be set to `true` for all requests. Requests without confirmed consent are rejected.

Proof of consent should be retained in line with POPIA and internal compliance requirements.

***

## FAQ

<details>

<summary>Why doesn't the initial POST return a result?</summary>

Verification is asynchronous — the verification supplier and Fraudcheck's back office process the check after submission. Poll `GET /driver-licence/status/{transaction_id}` until `results_available` is `true`, then fetch `GET /driver-licence/results/{transaction_id}`.

</details>

<details>

<summary>How long does processing take?</summary>

Typically 24-48 hours, depending on back-office processing volume. Poll the status endpoint rather than assuming a fixed delay.

</details>

<details>

<summary>What if the licence holder doesn't have a South African ID number?</summary>

Submit the passport/foreign document number in `IdentityNo` and supply `BirthDate` — this is required whenever `IdentityNo` doesn't pass SA ID checksum validation.

</details>

<details>

<summary>Can this verify a driver's licence issued by another country?</summary>

No. This service only verifies licences issued in South Africa. The licence holder can be a foreign national (a passport-holding non-citizen with an SA-issued licence is supported via `BirthDate`), but the licence itself must be SA-issued  `CountryCode` records the holder's own nationality, not the country whose registry is being checked.

</details>

***

## Changelog

| Date       | Version | Change           |
| ---------- | ------- | ---------------- |
| 2026-09-22 | v1.0    | Initial release. |
