> ## Documentation Index
> Fetch the complete documentation index at: https://www.niftipay.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Chargebacks & Fraud Protection

> View chargeback events, manage blocked IPs/emails, receive fraud alerts, and track chargeback statistics.

# Chargebacks & Fraud Protection

Chargebacks occur when a cardholder disputes a fiat payment. Niftipay provides a multi-layered fraud detection system that protects your business automatically.

This page covers:

* [How fraud protection works](#how-fraud-protection-works) — overview of the system
* [List chargebacks](#list-chargebacks) (`GET /api/fiat/chargebacks`)
* [Get a single chargeback](#get-chargeback) (`GET /api/fiat/chargebacks/:id`)
* [Chargeback statistics](#chargeback-statistics) (`GET /api/fiat/chargebacks/stats`)
* [Chargeback cases (blocked IPs & emails)](#chargeback-cases-blocked-ips--emails)
* [Fraud signals (order risk check)](#fraud-signals-order-risk-check) (`GET /api/fiat/orders/:identifier/fraud-signals`)
* [Fraud alert emails](#fraud-alert-emails)
* [Block page & contact URL](#block-page--contact-url)

> **New:** You can now proactively block IPs, emails, and card BINs without waiting for chargebacks. See [Fraud Prevention & Blocking](/api/fraud-prevention).

***

## How fraud protection works

Niftipay uses multiple signals to detect and prevent repeat fraud:

### 1. Automatic blocking (IP & email)

When a chargeback is recorded, Niftipay checks whether the same **IP address** or **email** has been involved in previous chargebacks for your account. If **2 or more** chargebacks share the same IP or email, that identifier is **automatically blocked** and a case is created.

When a blocked customer tries to pay via your checkout link, they see a block page with their case number instead of the payment form. You can [add a contact URL](#block-page--contact-url) so they can reach you if the block was a mistake.

Each block is **per merchant** — if you unblock an IP, it only affects your account. Other merchants' blocks are independent.

### 2. Manual blocking (IP, email, BIN)

You can proactively block IPs, emails, and card BINs **without waiting for chargebacks**. This is useful when you spot suspicious activity or know a particular card range is being used for fraud.

See the [Fraud Prevention & Blocking](/api/fraud-prevention) page for the full API reference.

### 3. BIN blocking

Block entire card ranges by their BIN (first 6 digits of the card number). When you notice fraud from cards sharing the same BIN (e.g. `443047`), block that BIN to prevent all cards in that range from completing checkout.

See [Block a Card BIN](/api/fraud-prevention#block-a-card-bin) for details.

### 4. Unusual amount detection

Niftipay monitors your order amounts and flags orders that are significantly higher than your average. If the same IP or email submits **2 or more** flagged orders within 24 hours, that identifier is **automatically blocked**.

See [Unusual Amount Detection](/api/fraud-prevention#unusual-amount-detection) for details.

### 5. Fraud alerts at payment time

When any order is **paid**, Niftipay checks the card number (last 4 digits), email, IP, card BIN, and order amount against:

* **Your own chargebacks** — full order details included in the alert
* **Platform-wide chargebacks from other merchants** — count and date included (no other merchant's details are exposed)
* **Blocked BINs** — flagged if the card BIN is on the blocklist
* **Amount anomalies** — flagged if the order amount is unusually high

If any signal matches, you receive a **fraud alert email** so you can review the order before shipping. This catches fraud even on the first order from a new customer if that card, email, or IP was flagged on another merchant's account.

### 6. Disposable email detection

Orders placed with disposable/temporary email addresses (e.g. `mailinator.com`, `guerrillamail.com`) are automatically flagged. This does **not** block the order, but the flag is included in fraud alert emails.

Niftipay checks against a database of 120,000+ known disposable email domains.

### 7. VPN / TOR / proxy detection

Before every checkout redirect, Niftipay checks the customer's IP against known VPN, TOR, and proxy networks. TOR and proxy traffic is blocked by default. This runs independently of the chargeback system.

***

## Base URL

All examples use:

* `https://www.niftipay.com`

***

## Authentication

These endpoints support **two authentication methods**:

### 1) API Key (recommended for integrations)

Send your API key in the `x-api-key` header.

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/chargebacks" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### 2) Session cookie (browser / dashboard usage)

If you are authenticated via the dashboard.

***

## Amounts are in minor units

All monetary values (`feeCents`, `orderAmountCents`, `amountCents`, `subtotalCents`) are stored in **minor units** (e.g. cents for EUR/USD).

To convert to the major unit, divide by 100 for most currencies. See [Fiat Orders](/api/fiat-orders) for details on currency decimal rules.

***

# List Chargebacks

## Endpoint

`GET /api/fiat/chargebacks`

> Requires API key or session authentication.

Returns a paginated list of chargeback events for the authenticated user, ordered by most recent first.

### Query parameters

| Name        | Type   | Default | Notes                                       |
| ----------- | ------ | ------- | ------------------------------------------- |
| `page`      | number | `1`     | Page number (min 1).                        |
| `pageSize`  | number | `25`    | Results per page. Min 1, max 500.           |
| `ipAddress` | string | —       | Optional. Filter chargebacks by IP address. |

### Example request

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/chargebacks?page=1&pageSize=25" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Example response

```json theme={null}
{
  "ok": true,
  "query": {
    "ipAddress": null,
    "page": 1,
    "pageSize": 25
  },
  "pageInfo": {
    "page": 1,
    "pageSize": 25,
    "total": 3,
    "totalPages": 1
  },
  "events": [
    {
      "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "userId": "u_abc123",
      "fiatOrderId": "ord_xyz789",
      "psp": "niftipayp1",
      "pspChargebackOrderId": "cb_001",
      "pspOriginalOrderId": "psp_order_001",
      "ipAddress": "203.0.113.42",
      "feeCents": 2500,
      "feeCurrency": "EUR",
      "feeDeducted": true,
      "feeDeductedAt": "2026-04-10T14:30:00.000Z",
      "orderAmountCents": 5000,
      "orderCurrency": "EUR",
      "createdAt": "2026-04-10T12:00:00.000Z",
      "order": {
        "id": "ord_xyz789",
        "orderKey": 10042,
        "merchantReference": "my-ref-001",
        "userId": "u_abc123",
        "psp": "niftipayp1",
        "pspOrderId": "psp_order_001",
        "status": "chargeback",
        "createdAt": "2026-04-08T09:00:00.000Z",
        "completedAt": "2026-04-08T09:05:00.000Z"
      }
    }
  ]
}
```

### Response fields

| Field                  | Type           | Description                                          |
| ---------------------- | -------------- | ---------------------------------------------------- |
| `id`                   | string         | Chargeback event ID.                                 |
| `userId`               | string         | Your user ID.                                        |
| `fiatOrderId`          | string         | The fiat order that was charged back.                |
| `psp`                  | string         | Payment service provider identifier.                 |
| `pspChargebackOrderId` | string         | The PSP's chargeback reference.                      |
| `pspOriginalOrderId`   | string \| null | The PSP's original order reference.                  |
| `ipAddress`            | string \| null | IP address associated with the chargeback.           |
| `feeCents`             | number         | Chargeback fee in minor units.                       |
| `feeCurrency`          | string         | Currency of the fee (e.g. `"EUR"`).                  |
| `feeDeducted`          | boolean        | Whether the fee has been deducted from your balance. |
| `feeDeductedAt`        | string \| null | ISO 8601 timestamp when the fee was deducted.        |
| `orderAmountCents`     | number \| null | Original order amount in minor units.                |
| `orderCurrency`        | string \| null | Currency of the original order.                      |
| `createdAt`            | string         | ISO 8601 timestamp when the chargeback was created.  |
| `order`                | object \| null | The linked fiat order (see below).                   |

#### Nested `order` object

| Field               | Type           | Description                                |
| ------------------- | -------------- | ------------------------------------------ |
| `id`                | string         | Fiat order ID.                             |
| `orderKey`          | number         | Numeric order key.                         |
| `merchantReference` | string \| null | Your merchant reference for this order.    |
| `userId`            | string         | Owner user ID.                             |
| `psp`               | string         | Payment service provider.                  |
| `pspOrderId`        | string         | PSP order reference.                       |
| `status`            | string         | Order status (e.g. `"chargeback"`).        |
| `createdAt`         | string         | ISO 8601 timestamp.                        |
| `completedAt`       | string \| null | ISO 8601 timestamp when payment completed. |

***

# Get Chargeback

## Endpoint

`GET /api/fiat/chargebacks/:id`

> Requires API key or session authentication.

Returns a single chargeback event by its ID, along with the linked fiat order details.

### Path parameters

| Name | Type   | Notes                    |
| ---- | ------ | ------------------------ |
| `id` | string | The chargeback event ID. |

### Example request

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/chargebacks/a1b2c3d4-5678-90ab-cdef-1234567890ab" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Example response

```json theme={null}
{
  "ok": true,
  "chargeback": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "userId": "u_abc123",
    "fiatOrderId": "ord_xyz789",
    "psp": "niftipayp1",
    "pspChargebackOrderId": "cb_001",
    "pspOriginalOrderId": "psp_order_001",
    "ipAddress": "203.0.113.42",
    "feeCents": 2500,
    "feeCurrency": "EUR",
    "feeDeducted": true,
    "feeDeductedAt": "2026-04-10T14:30:00.000Z",
    "orderAmountCents": 5000,
    "orderCurrency": "EUR",
    "createdAt": "2026-04-10T12:00:00.000Z"
  },
  "order": {
    "id": "ord_xyz789",
    "orderKey": 10042,
    "merchantReference": "my-ref-001",
    "status": "chargeback",
    "amountCents": 5000,
    "subtotalCents": 4750,
    "currency": "EUR",
    "psp": "niftipayp1",
    "pspOrderId": "psp_order_001",
    "createdAt": "2026-04-08T09:00:00.000Z",
    "completedAt": "2026-04-08T09:05:00.000Z"
  }
}
```

***

# Chargeback Statistics

## Endpoint

`GET /api/fiat/chargebacks/stats`

> Requires API key or session authentication.

Returns a daily breakdown of chargeback counts and amounts, plus overall chargeback rate.

### Example request

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/chargebacks/stats" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Example response

```json theme={null}
{
  "ok": true,
  "days": [
    {
      "dateYmd": "2026-04-08",
      "count": 2,
      "amountCents": 10000
    },
    {
      "dateYmd": "2026-04-10",
      "count": 1,
      "amountCents": 5000
    }
  ],
  "summary": {
    "totalChargebacks": 3,
    "totalPaidOrders": 150,
    "chargebackRatePercent": 2.0
  }
}
```

### Response fields

#### `days` array

| Field         | Type   | Description                                              |
| ------------- | ------ | -------------------------------------------------------- |
| `dateYmd`     | string | Date in `YYYY-MM-DD` format (Europe/Amsterdam timezone). |
| `count`       | number | Number of chargebacks on that day.                       |
| `amountCents` | number | Total chargeback amount in minor units for that day.     |

#### `summary` object

| Field                   | Type   | Description                                            |
| ----------------------- | ------ | ------------------------------------------------------ |
| `totalChargebacks`      | number | Total number of chargeback events.                     |
| `totalPaidOrders`       | number | Total number of paid orders (completed + chargeback).  |
| `chargebackRatePercent` | number | Chargeback rate as a percentage (e.g. `2.0` means 2%). |

***

# Error Responses

## Invalid query parameters (400)

```json theme={null}
{
  "ok": false,
  "error": "Invalid query",
  "details": { ... }
}
```

## Missing or invalid authentication (401)

```json theme={null}
{
  "ok": false,
  "error": "Unauthorized"
}
```

## Chargeback not found (404)

Returned by `GET /api/fiat/chargebacks/:id` when the ID does not exist or does not belong to your account.

```json theme={null}
{
  "ok": false,
  "error": "Chargeback not found"
}
```

***

# Chargeback Cases (Blocked IPs & Emails)

When an IP address or email appears in 2 or more chargebacks for your account, Niftipay automatically creates a **chargeback case** and blocks that identifier. Blocked customers see a message with their case number instead of being redirected to checkout.

Each case has a type: `ip` (blocked by IP address) or `email` (blocked by email address).

> **Merchant isolation:** Each case belongs to your account only. If you unblock an IP or email, it only affects your checkout. Other merchants' blocks are completely independent.

***

## List Chargeback Cases

### Endpoint

`GET /api/fiat/chargeback-cases`

> Requires API key or session authentication.

Returns a paginated list of chargeback cases for the authenticated user.

### Query parameters

| Name       | Type   | Default | Notes                                                  |
| ---------- | ------ | ------- | ------------------------------------------------------ |
| `page`     | number | `1`     | Page number (min 1).                                   |
| `pageSize` | number | `25`    | Results per page. Min 1, max 500.                      |
| `status`   | string | —       | Optional. Filter by `blocked` or `unblocked`.          |
| `search`   | string | —       | Optional. Search by case number, IP address, or email. |

### Example request

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/chargeback-cases?status=blocked" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Example response

```json theme={null}
{
  "ok": true,
  "query": {
    "status": "blocked",
    "search": null,
    "page": 1,
    "pageSize": 25
  },
  "pageInfo": {
    "page": 1,
    "pageSize": 25,
    "total": 2,
    "totalPages": 1
  },
  "cases": [
    {
      "id": 1,
      "caseNumber": "CB-00001",
      "kind": "ip",
      "ipAddress": "203.0.113.42",
      "blockedEmail": null,
      "status": "blocked",
      "chargebackEventIds": ["evt_aaa", "evt_bbb"],
      "cardNames": ["John Doe"],
      "truncatedPans": ["****1234"],
      "orderEmails": ["john@example.com"],
      "createdAt": "2026-04-10T12:00:00.000Z",
      "unblockedAt": null,
      "unblockedReason": null
    },
    {
      "id": 2,
      "caseNumber": "CB-00002",
      "kind": "email",
      "ipAddress": null,
      "blockedEmail": "fraudster@tempmail.com",
      "status": "blocked",
      "chargebackEventIds": ["evt_ccc", "evt_ddd"],
      "cardNames": ["Jane Smith", "J Smith"],
      "truncatedPans": ["****5678", "****9012"],
      "orderEmails": ["fraudster@tempmail.com"],
      "createdAt": "2026-04-11T08:30:00.000Z",
      "unblockedAt": null,
      "unblockedReason": null
    }
  ]
}
```

### Response fields (case object)

| Field                | Type           | Description                                                               |
| -------------------- | -------------- | ------------------------------------------------------------------------- |
| `id`                 | number         | Case ID (used in URLs).                                                   |
| `caseNumber`         | string         | Human-readable case number (e.g. `CB-00001`). Shown to blocked customers. |
| `kind`               | string         | Block type: `"ip"` or `"email"`.                                          |
| `ipAddress`          | string \| null | Blocked IP address (for `ip` kind cases).                                 |
| `blockedEmail`       | string \| null | Blocked email address (for `email` kind cases).                           |
| `status`             | string         | `"blocked"` or `"unblocked"`.                                             |
| `chargebackEventIds` | string\[]      | IDs of the chargeback events that triggered this case.                    |
| `cardNames`          | string\[]      | Cardholder names from the flagged orders.                                 |
| `truncatedPans`      | string\[]      | Truncated card numbers (last 4 digits) from the flagged orders.           |
| `orderEmails`        | string\[]      | Email addresses used in the flagged orders.                               |
| `createdAt`          | string         | ISO 8601 timestamp when the case was created.                             |
| `unblockedAt`        | string \| null | ISO 8601 timestamp when the case was unblocked.                           |
| `unblockedReason`    | string \| null | Reason provided when unblocking.                                          |

***

## Get Chargeback Case

### Endpoint

`GET /api/fiat/chargeback-cases/:id`

> Requires API key or session authentication.

Returns a single chargeback case with its related chargeback events and order details.

### Path parameters

| Name | Type   | Notes        |
| ---- | ------ | ------------ |
| `id` | number | The case ID. |

### Example request

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/chargeback-cases/1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Example response

```json theme={null}
{
  "ok": true,
  "case": {
    "id": 1,
    "caseNumber": "CB-00001",
    "kind": "ip",
    "ipAddress": "203.0.113.42",
    "blockedEmail": null,
    "status": "blocked",
    "chargebackEventIds": ["evt_aaa", "evt_bbb"],
    "cardNames": ["John Doe"],
    "truncatedPans": ["****1234"],
    "orderEmails": ["john@example.com"],
    "createdAt": "2026-04-10T12:00:00.000Z",
    "unblockedAt": null,
    "unblockedReason": null
  },
  "chargebackEvents": [
    {
      "id": "evt_aaa",
      "ipAddress": "203.0.113.42",
      "feeCents": 4500,
      "feeCurrency": "EUR",
      "feeDeducted": true,
      "orderAmountCents": 5000,
      "orderCurrency": "EUR",
      "createdAt": "2026-04-10T12:00:00.000Z",
      "orderKey": 10042,
      "merchantReference": "my-ref-001",
      "orderStatus": "chargeback",
      "orderEmail": "john@example.com",
      "cardholderName": "John Doe",
      "truncatedPan": "****1234",
      "cardCountry": "NL",
      "orderCompletedAt": "2026-04-08T09:05:00.000Z"
    }
  ]
}
```

***

## Unblock a Case

### Endpoint

`PATCH /api/fiat/chargeback-cases/:id`

> Requires API key or session authentication.

Unblocks an IP or email, allowing orders from that identifier to proceed again. If a new chargeback is later recorded from the same identifier, the case will be **automatically re-blocked**.

> You can only unblock your own cases. Other merchants' blocks are not affected.

### Path parameters

| Name | Type   | Notes        |
| ---- | ------ | ------------ |
| `id` | number | The case ID. |

### Request body

```json theme={null}
{
  "action": "unblock",
  "reason": "Customer verified identity via phone call"
}
```

| Field    | Type   | Required | Notes                                                |
| -------- | ------ | -------- | ---------------------------------------------------- |
| `action` | string | Yes      | Must be `"unblock"`.                                 |
| `reason` | string | No       | Optional reason for unblocking (max 500 characters). |

### Example request

```bash theme={null}
curl -X PATCH "https://www.niftipay.com/api/fiat/chargeback-cases/1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "unblock", "reason": "Customer verified identity"}'
```

### Example response

```json theme={null}
{
  "ok": true,
  "case": {
    "id": 1,
    "caseNumber": "CB-00001",
    "kind": "ip",
    "ipAddress": "203.0.113.42",
    "blockedEmail": null,
    "status": "unblocked",
    "chargebackEventIds": ["evt_aaa", "evt_bbb"],
    "cardNames": ["John Doe"],
    "truncatedPans": ["****1234"],
    "orderEmails": ["john@example.com"],
    "createdAt": "2026-04-10T12:00:00.000Z",
    "unblockedAt": "2026-04-12T10:00:00.000Z",
    "unblockedReason": "Customer verified identity"
  }
}
```

### Error: already unblocked (409)

```json theme={null}
{
  "ok": false,
  "error": "Case is already unblocked"
}
```

***

# Fraud Signals (Order Risk Check)

## Endpoint

`GET /api/fiat/orders/:identifier/fraud-signals`

> Requires API key or session authentication.

Returns a comprehensive fraud risk assessment for a single fiat order. Checks the order's card number, email, and IP address against all chargeback records (both your own and platform-wide), checks for active blocks, detects disposable emails, and computes an IP risk score — all in a single request.

This endpoint is used by the [WooCommerce plugin](/api/examples) to display real-time fraud warnings on the order detail page.

### Path parameters

| Name         | Type   | Notes                                                                                                         |
| ------------ | ------ | ------------------------------------------------------------------------------------------------------------- |
| `identifier` | string | The fiat order identifier. Can be an `orderKey` (digits), order `id` (UUID), or `merchantReference` (string). |

### Example request

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/fiat/orders/10042/fraud-signals" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Example response

```json theme={null}
{
  "ok": true,
  "order": {
    "id": "ord_xyz789",
    "orderKey": 10042,
    "merchantReference": "WC-456",
    "email": "buyer@example.com",
    "ip": "203.0.113.42",
    "truncatedPan": "1234",
    "bin": "460332",
    "cardholderName": "John Doe"
  },
  "severity": "high",
  "signals": [
    {
      "type": "pan_merchant",
      "label": "Card ****1234 matched 2 of your chargeback(s)",
      "count": 2,
      "matches": [
        {
          "signal": "pan",
          "cbOrderKey": "#10010",
          "cbRef": "WC-100",
          "cbAmount": "50.00 EUR",
          "cbDate": "2026-03-01",
          "cbCardholderName": "John Doe"
        }
      ]
    },
    {
      "type": "ip_platform",
      "label": "IP flagged in 3 chargeback(s) across platform",
      "count": 3,
      "latestAmount": "120.00 EUR",
      "latestDate": "2026-04-10"
    },
    {
      "type": "disposable_email",
      "label": "Disposable/temporary email detected"
    }
  ],
  "ipRisk": {
    "score": 62,
    "label": "high",
    "components": {
      "count": 30,
      "recency": 22,
      "velocity": 5,
      "spread": 6
    },
    "reasons": [
      "Total chargeback events: 15.",
      "Last seen 0.5 days ago.",
      "Velocity: last1d=0, last7d=2, last30d=5.",
      "Spread: distinct merchants=2, distinct PSPs=1."
    ],
    "stats": {
      "total": 15,
      "distinctMerchants": 2,
      "distinctPsps": 1,
      "last1d": 0,
      "last7d": 2,
      "last30d": 5,
      "firstSeenAt": "2026-01-15T10:30:00.000Z",
      "lastSeenAt": "2026-04-14T14:22:00.000Z",
      "daysSinceLastSeen": 0.567
    }
  }
}
```

### Response fields

| Field      | Type   | Description                                                         |
| ---------- | ------ | ------------------------------------------------------------------- |
| `order`    | object | Summary of the order being checked (see below).                     |
| `severity` | string | Overall risk level: `"critical"`, `"high"`, `"medium"`, or `"low"`. |
| `signals`  | array  | List of fraud signals detected (see below). Empty array if clean.   |
| `ipRisk`   | object | IP risk scoring details (see below).                                |

#### `order` object

| Field               | Type           | Description                                                                                 |
| ------------------- | -------------- | ------------------------------------------------------------------------------------------- |
| `id`                | string         | Fiat order ID.                                                                              |
| `orderKey`          | number         | Numeric order key.                                                                          |
| `merchantReference` | string \| null | Your merchant reference.                                                                    |
| `email`             | string \| null | Customer email on the order.                                                                |
| `ip`                | string \| null | Customer IP address (captured at checkout or from PSP).                                     |
| `truncatedPan`      | string \| null | Last 4 digits of the card used.                                                             |
| `bin`               | string \| null | Card BIN (first 6 digits). Used for [BIN blocking](/api/fraud-prevention#block-a-card-bin). |
| `cardholderName`    | string \| null | Cardholder name from the PSP.                                                               |

#### `severity` levels

| Level      | Meaning                                                                                                       |
| ---------- | ------------------------------------------------------------------------------------------------------------- |
| `critical` | IP/email blocked, BIN blocked, velocity auto-block, or IP risk score >= 75. **Do not fulfil without review.** |
| `high`     | Card/email/IP matched your chargebacks, critical amount anomaly (z-score >= 5.0), or IP risk score >= 50.     |
| `medium`   | Platform-wide matches, disposable email, or warning amount anomaly (z-score >= 3.0).                          |
| `low`      | No fraud signals detected.                                                                                    |

#### `signals` array

Each signal is an object with a `type` field. The possible types are:

| Type                    | Description                                                                                                       | Extra fields                                        |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `pan_merchant`          | Card matched your own chargebacks.                                                                                | `count`, `matches[]`                                |
| `email_merchant`        | Email matched your own chargebacks.                                                                               | `count`, `matches[]`                                |
| `ip_merchant`           | IP matched your own chargebacks.                                                                                  | `count`, `matches[]`                                |
| `pan_platform`          | Card flagged in chargebacks across other merchants.                                                               | `count`, `latestAmount`, `latestDate`               |
| `email_platform`        | Email flagged across other merchants.                                                                             | `count`, `latestAmount`, `latestDate`               |
| `ip_platform`           | IP flagged across other merchants.                                                                                | `count`, `latestAmount`, `latestDate`               |
| `disposable_email`      | Email uses a known disposable/temporary domain.                                                                   | —                                                   |
| `ip_blocked`            | IP is currently blocked by a chargeback case.                                                                     | `caseNumber`                                        |
| `email_blocked`         | Email is currently blocked by a chargeback case.                                                                  | `caseNumber`                                        |
| `bin_blocked`           | Card BIN is on the blocklist. See [BIN blocking](/api/fraud-prevention#block-a-card-bin).                         | `bin`, `reason`                                     |
| `amount_anomaly`        | Order amount is unusually high. See [amount detection](/api/fraud-prevention#unusual-amount-detection).           | `zScore`, `severity`, `merchantMean`, `amountCents` |
| `ip_amount_velocity`    | IP auto-blocked for repeated high-amount orders. See [velocity](/api/fraud-prevention#velocity-auto-blocking).    | `anomalyCount`, `caseNumber`                        |
| `email_amount_velocity` | Email auto-blocked for repeated high-amount orders. See [velocity](/api/fraud-prevention#velocity-auto-blocking). | `anomalyCount`, `caseNumber`                        |

**Merchant-level matches** (`*_merchant`) include a `matches` array with full order details:

| Field              | Type   | Description                                             |
| ------------------ | ------ | ------------------------------------------------------- |
| `signal`           | string | `"pan"`, `"email"`, or `"ip"`.                          |
| `cbOrderKey`       | string | Order key of the matching chargeback (e.g. `"#10042"`). |
| `cbRef`            | string | Merchant reference of the matching order.               |
| `cbAmount`         | string | Amount and currency (e.g. `"50.00 EUR"`).               |
| `cbDate`           | string | Date of the chargeback (`YYYY-MM-DD`).                  |
| `cbCardholderName` | string | Cardholder name from the matching order.                |

**Platform-level matches** (`*_platform`) only include a count and most recent amount/date — no other merchant's details are exposed.

#### `ipRisk` object

| Field        | Type           | Description                                                                                                                                                             |
| ------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `score`      | number         | Risk score from 0 (safe) to 100 (very high risk).                                                                                                                       |
| `label`      | string         | `"low"` (0-19), `"medium"` (20-49), `"high"` (50-74), `"critical"` (75+).                                                                                               |
| `components` | object         | Score breakdown: `count` (0-40), `recency` (0-25), `velocity` (0-15), `spread` (0-20).                                                                                  |
| `reasons`    | string\[]      | Human-readable explanations for the score.                                                                                                                              |
| `stats`      | object \| null | Raw statistics: `total`, `distinctMerchants`, `distinctPsps`, `last1d`, `last7d`, `last30d`, `firstSeenAt`, `lastSeenAt`, `daysSinceLastSeen`. Null if no IP available. |

### Error responses

#### Order not found (404)

```json theme={null}
{
  "ok": false,
  "error": "Not found"
}
```

#### Not a fiat order / invalid identifier (400)

```json theme={null}
{
  "ok": false,
  "error": "Invalid identifier"
}
```

#### Ambiguous merchant reference (409)

If your `merchantReference` matches multiple orders:

```json theme={null}
{
  "ok": false,
  "error": "Ambiguous merchantReference"
}
```

Use the numeric `orderKey` or UUID `id` instead.

***

# Fraud Alert Emails

Niftipay sends you an email when a **paid order** matches previous chargeback signals. These alerts are sent automatically — no API configuration needed.

### What triggers an alert

When an order completes payment, Niftipay checks three signals against **your own chargebacks** and **chargebacks across the entire platform** (from other merchants):

| Signal                          | Your chargebacks                 | Platform-wide                                 |
| ------------------------------- | -------------------------------- | --------------------------------------------- |
| **Card number** (last 4 digits) | Full order details shown         | Count + date only (no other merchant details) |
| **Email address**               | Full order details shown         | Count + date only                             |
| **IP address**                  | Full order details shown         | Count + date only                             |
| **Disposable email**            | Flagged in the alert             | —                                             |
| **Blocked BIN**                 | Flagged with BIN and reason      | —                                             |
| **Unusual amount**              | Flagged with z-score and average | —                                             |

If any signal matches, you receive a single email with all risk signals and related chargebacks.

### Example alert email contents

```
Risk signals:
  ⚠ Card (last 4: ****1234) matched 1 of your chargeback(s)
  ⚠ Card (last 4: ****1234) flagged in 3 chargeback(s) across the platform
  ⚠ Disposable/temporary email detected (user@mailinator.com)

Your chargebacks:
  [Card] Order #10042 (POS-1234) — 50.00 EUR — 2026-04-08

Platform-wide chargebacks (other merchants):
  [Card] 3 chargeback(s) — most recent: 120.00 EUR — 2026-04-12
```

> **Privacy:** Platform-wide alerts never expose other merchants' order numbers, references, or identities. Only the signal type, count, and most recent date/amount are shown.

### What to do when you receive an alert

* **Review the order** in your dashboard before shipping any goods.
* If the order looks legitimate, no action is needed.
* If the order looks fraudulent, you can cancel or refund it from the dashboard.

***

# Block Page & Contact URL

When a customer is blocked, they see a page like this:

> **There's a problem with your order**
>
> Case number: #CB-00042
>
> Please contact the shop for assistance.
>
> \[Contact Shop] ← button (only if you configured a contact URL)

### Setting up a contact URL

You can add a `contactUrl` to your fiat integration so blocked customers can reach you directly. The "Contact Shop" button links to this URL.

To set it, update your integration via the API:

```bash theme={null}
curl -X PATCH "https://www.niftipay.com/api/fiat/integrations/YOUR_INTEGRATION_ID" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contactUrl": "https://myshop.com/contact"}'
```

To remove it, set it to `null`:

```bash theme={null}
curl -X PATCH "https://www.niftipay.com/api/fiat/integrations/YOUR_INTEGRATION_ID" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contactUrl": null}'
```

This field is optional. If not set, the block page shows only the case number and a text message asking the customer to contact you.

See [Fiat Integrations](/api/fiat-integrations) for the full integration management API.
