> 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/identity/sim-swap-check.md).

# SIM Swap Check

SIM Swap Check identifies whether a mobile number has recently been transferred to a new SIM card. A recent SIM swap is a strong indicator of account-takeover fraud, where an attacker tricks a mobile operator into porting a victim's number so they can intercept SMS one-time passwords. Use this service to surface that risk before authorising sensitive actions.

## When to use this

Use this service to:

* Detect potential account-takeover attempts before sending an SMS OTP
* Block or step up authentication on high-value transactions when a number has recently been swapped
* Flag accounts for fraud review when frequent SIM changes are observed
* Support account recovery decisions

## How it works

Submit the mobile number along with the consumer's ID number and name in a single POST request. The service queries telecom records, retrieves the SIM change history for the number, and returns a synchronous response containing the swap status, the date of the most recent swap, swap counts over 6 and 12 months, and an overall risk indicator. Recent swaps (within 30 days) are treated as the highest risk.

| Property              | Value           |
| --------------------- | --------------- |
| Response type         | `Synchronous`   |
| Typical response time | < 5s            |
| Result retrieval      | Returned inline |
| Consent required      | `Yes`           |
| Region                | South Africa    |

***

## Authentication

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

***

## Endpoint

```http
POST /sim-swap
```

***

## 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                                                           |
| `CellNo`                       | string  | Yes      | South African mobile number. Local (`0721234567`) or international (`27721234567`) format. |
| `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",
  "CellNo": "0721234567",
  "ConsentObtainedByDataSubject": true
}
```

***

## Response

### Response fields

| Field            | Type   | Description                        |
| ---------------- | ------ | ---------------------------------- |
| `transaction_id` | string | Unique identifier for this request |
| `identifier`     | string | ID number submitted                |
| `cell_no`        | string | Mobile number checked              |
| `first_name`     | string | First name submitted               |
| `last_name`      | string | Surname submitted                  |
| `SimSwapDetails` | object | Container for SIM swap result      |

### `SimSwapDetails` fields

| Field              | Type           | Description                                                |
| ------------------ | -------------- | ---------------------------------------------------------- |
| `swap_detected`    | boolean        | `true` if a recent SIM swap was found                      |
| `last_swap_date`   | string \| null | Date of the most recent SIM swap (`YYYY-MM-DD`), or `null` |
| `swap_count_6m`    | integer        | Number of SIM swaps in the last 6 months                   |
| `swap_count_12m`   | integer        | Number of SIM swaps in the last 12 months                  |
| `risk_indicator`   | string         | `LOW`, `MEDIUM`, or `HIGH`                                 |
| `network_operator` | string         | Mobile network operator (e.g. `Vodacom`, `MTN`)            |
| `line_status`      | string         | Line status (e.g. `Active`, `Suspended`)                   |

### Risk indicator logic

| Condition                                          | `risk_indicator` |
| -------------------------------------------------- | ---------------- |
| No SIM swap detected                               | `LOW`            |
| Last swap > 90 days ago                            | `LOW`            |
| Last swap 30–90 days ago                           | `MEDIUM`         |
| Last swap within 30 days, or frequent recent swaps | `HIGH`           |

### Example response - no swap detected

```json
{
  "transaction_id": "TXN20231215120540001",
  "identifier": "8601015800086",
  "cell_no": "0721234567",
  "first_name": "JOHN",
  "last_name": "SMITH",
  "product": "consumer_sim_swap",
  "SimSwapDetails": {}
}
```

### Example response - recent swap detected

```json
{
  "transaction_id": "TXN20231215120540002",
  "identifier": "***********",
  "cell_no": "0721234567",
  "first_name": "JOHN",
  "last_name": "SMITH",
 "product": "consumer_sim_swap",
  "SimSwapDetails": {
    "CellNumber": "0721234567",
        "SimSwapResult": "Sim has been swapped within the last  6month(s)",
        "RiskFlag": "Sim Swapped"
  }
}
```

***

## Errors

| HTTP | Code            | Meaning                              | Action                           |
| ---- | --------------- | ------------------------------------ | -------------------------------- |
| 400  | `bad_request`   | Missing or malformed `CellNo`        | Provide a valid SA mobile number |
| 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               | See `details.field`              |
| 500  | `server_error`  | Unexpected error                     | Contact support                  |

***

## Recommended decisioning

A simple decisioning pattern using the response:

| Outcome                                         | Recommended action                                                               |
| ----------------------------------------------- | -------------------------------------------------------------------------------- |
| `swap_detected: false`, `risk_indicator: LOW`   | Proceed with normal flow                                                         |
| `swap_detected: true`, `risk_indicator: MEDIUM` | Step up authentication (e.g. additional verification before allowing the action) |
| `swap_detected: true`, `risk_indicator: HIGH`   | Block SMS OTP delivery; require an out-of-band verification channel              |
| `swap_count_12m` ≥ 3                            | Flag account for manual fraud review                                             |

***

## Code examples

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

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

curl -X POST "$BASE_URL/sim-swap" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "IdentityNo": "8601015800086",
    "FirstName": "John",
    "LastName": "Smith",
    "CellNo": "0721234567",
    "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}/sim-swap",
    headers={
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
    },
    json={
        "IdentityNo": "8601015800086",
        "FirstName": "John",
        "LastName": "Smith",
        "CellNo": "0721234567",
        "ConsentObtainedByDataSubject": True,
    },
)
data = response.json()
details = data["SimSwapDetails"]

if details["swap_detected"]:
    print(f"⚠️  SIM swap detected - risk: {details['risk_indicator']}")
    print(f"Last swap: {details['last_swap_date']}")
else:
    print(f"No SIM swap detected - risk: {details['risk_indicator']}")
```

{% 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}/sim-swap`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${accessToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    IdentityNo: "8601015800086",
    FirstName: "John",
    LastName: "Smith",
    CellNo: "0721234567",
    ConsentObtainedByDataSubject: true,
  }),
});
const data = await response.json();
const details = data.SimSwapDetails;

if (details.swap_detected) {
  console.warn(`SIM swap detected (${details.risk_indicator}) on ${details.last_swap_date}`);
} else {
  console.log(`No SIM swap detected - risk: ${details.risk_indicator}`);
}
```

{% 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 in line with POPIA requirements.

***

## FAQ

<details>

<summary>What counts as a "recent" SIM swap?</summary>

A swap within the last 30 days is treated as the highest risk. Swaps between 30 and 90 days old are medium risk; older than 90 days drops back to low risk.

</details>

<details>

<summary>Can I check any mobile number?</summary>

Only South African mobile numbers from supported network operators are covered.

</details>

<details>

<summary>What format should `CellNo` be in?</summary>

Either local (`0721234567`) or international (`27721234567`) format is accepted.

</details>

<details>

<summary>Why might a number return `MEDIUM` risk with no recent swap?</summary>

Frequent historical swaps over the last 12 months can elevate the risk indicator even if the most recent swap is older than 30 days.

</details>

***

## Changelog

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


---

# 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/identity/sim-swap-check.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.
