> 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/address-lookup.md).

# Address Lookup

Address Lookup returns the known address history for a consumer based on their South African ID number. Use it to confirm a stated address against verified records, surface previous addresses, or flag inconsistencies during onboarding and KYC checks.

## When to use this

Use this service to:

* Verify a consumer's stated address against verified records
* Retrieve up to four historical addresses for a consumer
* Detect address inconsistencies that may indicate fraud
* Support KYC and onboarding workflows

{% hint style="info" %}
Address data reflects records previously reported to verified consumer databases - namely consumer credit databases. It is not a live query against a government or postal database.
{% endhint %}

## How it works

Submit an ID number, first name, surname, and consent flag in a single POST request. The service looks up the consumer in the verified address database and returns their demographic details and address history synchronously. If no records are found, the response is still successful with an empty address history.

| Property              | Value                       |
| --------------------- | --------------------------- |
| Response type         | `Synchronous`               |
| Typical response time | < 5s (up to 60s under load) |
| Result retrieval      | Returned inline             |
| Consent required      | `Yes` (mandatory)           |
| Region                | South Africa                |

## Authentication

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

## Endpoint

```http
POST /address-lookup/verify
```

## 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. |

### Example request

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

## Response

### Response fields

| Field              | Type    | Description                                        |
| ------------------ | ------- | -------------------------------------------------- |
| `success`          | boolean | Whether the request was processed                  |
| `transaction_id`   | string  | Unique identifier for this request                 |
| `screening_result` | string  | `ACCEPT`, `REVIEW`, or `REJECT`                    |
| `lookup_result`    | object  | Container for consumer details and address history |

### `lookup_result.consumer_info` fields

Consumer demographic details. Empty `{}` if no record was found.

| Field                 | Type   | Description                           |
| --------------------- | ------ | ------------------------------------- |
| `surname`             | string | Surname on file                       |
| `forename1`           | string | First name on file                    |
| `gender`              | string | `M` or `F`                            |
| `date_of_birth`       | string | Date of birth (`YYYYMMDD`)            |
| `identity_no`         | string | ID number on file                     |
| `marital_status_desc` | string | Marital status (e.g. `SINGLE`)        |
| `deceased_date`       | string | Deceased date, or `0` if not deceased |

### `lookup_result.address_history[]` fields

Up to 4 addresses, ordered most recent first. Empty `[]` if none on file.

| Field              | Type   | Description                                |
| ------------------ | ------ | ------------------------------------------ |
| `line1`            | string | Address line 1                             |
| `suburb`           | string | Suburb                                     |
| `city`             | string | City                                       |
| `postal_code`      | string | Postal code                                |
| `province`         | string | Province name                              |
| `information_date` | string | Date the address was reported (`YYYYMMDD`) |
| `address_period`   | string | Months at this address                     |
| `owner_tenant`     | string | `O` = Owner, `T` = Tenant                  |

### Screening result logic

| Result   | Meaning                                            |
| -------- | -------------------------------------------------- |
| `ACCEPT` | Identity matched and at least one address returned |
| `REVIEW` | Identity matched but no addresses on file          |
| `REJECT` | Identity not found in the consumer database        |

### Example response - addresses found

```json
{
  "success": true,
  "transaction_id": "d41d8cd98f00b204e9800998ecf8427e",
  "screening_result": "ACCEPT",
  "lookup_result": {
    "success": true,
    "consumer_info": {
      "surname": "SMITH",
      "forename1": "JOHN",
      "gender": "M",
      "date_of_birth": "19860101",
      "identity_no": "8601015800086",
      "marital_status_desc": "SINGLE",
      "deceased_date": "0"
    },
    "address_history": [
      {
        "line1": "12 MAIN ROAD",
        "suburb": "SANDTON",
        "city": "JOHANNESBURG",
        "postal_code": "2196",
        "province": "GAUTENG",
        "information_date": "20210527",
        "address_period": "24",
        "owner_tenant": "O"
      }
    ]
  }
}
```

### Example response - no addresses on file

```json
{
  "success": true,
  "transaction_id": "d41d8cd98f00b204e9800998ecf8427e",
  "screening_result": "REVIEW",
  "lookup_result": {
    "success": true,
    "consumer_info": {},
    "address_history": []
  }
}
```

## Errors

| HTTP | Code                  | Meaning                                                             | Action                                                |
| ---- | --------------------- | ------------------------------------------------------------------- | ----------------------------------------------------- |
| 400  | `bad_request`         | Missing required field or `ConsentObtainedByDataSubject` not `true` | Set consent to `true` and 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                          |
| 502  | `service_unavailable` | Upstream lookup service unavailable                                 | Retry with exponential backoff                        |
| 500  | `server_error`        | Unexpected error                                                    | Contact support                                       |

{% hint style="info" %}
An identity that cannot be found returns HTTP `200` with `screening_result: "REJECT"` - it is a successful API call with a negative result, not an error.
{% endhint %}

## Code examples

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

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

curl -X POST "$BASE_URL/address-lookup/verify" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "IdentityNo": "8601015800086",
    "FirstName": "John",
    "LastName": "Smith",
    "ConsentObtainedByDataSubject": true
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

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

response = requests.post(
    f"{BASE_URL}/address-lookup/verify",
    headers={
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
    },
    json={
        "IdentityNo": "8601015800086",
        "FirstName": "John",
        "LastName": "Smith",
        "ConsentObtainedByDataSubject": True,
    },
)
result = response.json()

print(f"Screening: {result['screening_result']}")
for addr in result["lookup_result"].get("address_history", []):
    print(f"{addr['line1']}, {addr['suburb']}, {addr['city']}, {addr['province']} {addr['postal_code']}")
```

{% endtab %}

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

```javascript
const BASE_URL = "https://consumer-service-api.fraudcheckonline.co.za/consumer-service";

const response = await fetch(`${BASE_URL}/address-lookup/verify`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${accessToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    IdentityNo: "8601015800086",
    FirstName: "John",
    LastName: "Smith",
    ConsentObtainedByDataSubject: true,
  }),
});
const result = await response.json();

const addresses = result.lookup_result?.address_history ?? [];
addresses.forEach(a => console.log(`${a.line1}, ${a.city}, ${a.province}`));
```

{% endtab %}
{% endtabs %}

## Compliance & consent

* Consent is mandatory. Requests without `ConsentObtainedByDataSubject: true` are rejected with HTTP `400`.
* Obtain explicit consent from the data subject before submitting.
* Retain proof of consent in line with POPIA requirements.

## FAQ

<details>

<summary>How current are the addresses returned?</summary>

Addresses reflect records previously reported to verified consumer credit databases. They represent known historical addresses and may not be the consumer's current residence.

</details>

<details>

<summary>How many addresses can be returned?</summary>

Up to four addresses, ordered most recent first.

</details>

<details>

<summary>What does an empty `address_history` mean?</summary>

The consumer was found but has no addresses on file. The response returns `screening_result: "REVIEW"` and is not an error.

</details>

<details>

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

Up to 60 seconds.

</details>

## Changelog

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