# CVV Filters

Configure Card Verification Value (CVV) filters to prevent fraudulent transactions.

---

## Overview

CVV (Card Verification Value) is the 3-4 digit security code on the back (or front for Amex) of credit cards. CVV verification confirms the customer has physical possession of the card. Use CVV filters to:

- 🛡️ **Prevent fraud** - Decline approved sales whose CVV result you do not accept
- 🔐 **Require CVV** - Decline keyed card sales submitted without a CVV (per gateway)
- ⚙️ **Two layers** - A merchant-wide filter (Fraud Prevention settings) and per-gateway rules (Gateways tab)

A CVV filter decline marks the transaction `declined` with response code `225` and response text `Do Not Honor – CVV Verification Failed`. Filters only apply to card payments.

---

## Get CVV Settings

AVS and CVV filters share one merchant-level settings object.

### Endpoint

```http
GET /api/v1/merchants/:merchantId/fraud-settings
```

```bash
curl https://uat.auxcore.net/api/v1/merchants/3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90/fraud-settings \
  -H "Authorization: Bearer YOUR_TOKEN"
```

**Response:**
```json
{
  "success": true,
  "data": {
    "enabled": true,
    "avsRejectCodes": ["noMatch"],
    "cvvRejectCodes": ["noMatch", "notProcessed"],
    "rejectOnUnavailable": false,
    "rejectOnError": false,
    "rejectOnNoMatch": true,
    "rejectOnPartialMatch": false
  }
}
```

See [AVS Filters](./avs.md) for the full field reference and status codes.

---

## Update CVV Settings

### Endpoint

```http
PUT /api/v1/merchants/:merchantId/fraud-settings
```

Requires the `business.manage` permission. The body **replaces** the whole settings object, so send `avsRejectCodes` too or it resets to `[]`.

```bash
curl -X PUT https://uat.auxcore.net/api/v1/merchants/3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90/fraud-settings \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "avsRejectCodes": ["noMatch"],
    "cvvRejectCodes": ["noMatch", "notProcessed"]
  }'
```

**Response:** `200` with the saved settings in `data` and `"message": "Fraud prevention settings updated successfully"`.

---

## CVV Reject Categories

`cvvRejectCodes` takes category keys, not raw CVV letters:

| Key | CVV code declined | Meaning |
|-----|-------------------|---------|
| `noMatch` | `N` | CVV does not match |
| `notProcessed` | `P` | CVV not processed |
| `notProvided` | `S` | CVV should be on the card but was not provided / not supported |
| `issuerNotCertified` | `U` | Issuer not certified / information unavailable |

The filter is stored as an allow-list of `M`, `N`, `P`, `S`, `U` minus the ones you reject. `M` (match) is never declined. If `cvvRejectCodes` is empty (or `enabled` is `false`), CVV never declines at the merchant level. Once at least one key is selected, any code **outside** those five letters (for example `X`) is also declined. Settings reach the filter through a background sync to the card-security service (see the note on [AVS Filters](./avs.md)), and the filter fails open if that service cannot be reached.

### CVV Response Codes

| Code | Meaning |
|------|---------|
| **M** | CVV matches |
| **N** | CVV does not match |
| **P** | Not processed |
| **S** | Not provided / not supported |
| **U** | Issuer not certified / unavailable |

> **Note:** Not every processor returns a CVV result code. TSYS, for example, returns none and signals a CVV mismatch by declining the authorization itself. When no CVV result comes back, the CVV filters have nothing to evaluate.

---

## Per-Gateway CVV Rules

Each processor account (Gateways tab) can carry its own CVV rules, evaluated before the merchant-level filter against the gateway that actually processed the sale.

```http
PUT /api/v1/merchants/:merchantId/gateways/:id
```

```json
{
  "requireCVV": true,
  "cvvRules": {
    "rejectOnMismatch": true,
    "allowedResponses": ["M"]
  }
}
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `requireCVV` | boolean | `true` | Decline a keyed card sale submitted without a CVV |
| `cvvRules.rejectOnMismatch` | boolean | — | When `true`, any CVV code not in `allowedResponses` declines |
| `cvvRules.allowedResponses` | string[] | — | Accepted CVV letters (case-insensitive) |

### How `requireCVV` is enforced

`requireCVV` is checked **before** authorization, on the submitted request — not on the gateway's answer:

- It applies only when the raw card number is sent to AuxCORE. Tokenized capture (PCI hosted fields / vault token) hides the CVV from the API, so it is not enforced there. Raw card data is rejected on Sandbox and Production, so in practice this check does not fire for API integrations.
- Recurring, installment and card-on-file (merchant-initiated) charges are exempt.
- A missing CVV is rejected with `ValidationError` `CVV is required for this payment`; the transaction is stored as `declined` with response code `225` and text `Do Not Honor – CVV Required`.

---

## Preset Configurations

### Strict (Recommended)

Decline anything that is not a match:

```json
{
  "enabled": true,
  "avsRejectCodes": ["noMatch"],
  "cvvRejectCodes": ["noMatch", "notProcessed", "notProvided", "issuerNotCertified"]
}
```

### Balanced

Decline mismatches only:

```json
{
  "enabled": true,
  "avsRejectCodes": ["noMatch"],
  "cvvRejectCodes": ["noMatch"]
}
```

---

## Transaction Response

The public transaction response returns the gateway's CVV code in `data.CvvResult`:

```json
{
  "success": true,
  "status": "success",
  "status_code": 200,
  "message": "Transaction approved",
  "data": {
    "TransactionId": "8d1c2b3a-4e5f-4a6b-9c7d-0e1f2a3b4c5d",
    "Status": "1",
    "ResponseCode": "100",
    "AvsResult": "Y",
    "CvvResult": "M"
  }
}
```

### Declined by CVV

Returned with HTTP `402`:

```json
{
  "success": false,
  "status": "declined",
  "status_code": 402,
  "message": "Do Not Honor – CVV Verification Failed",
  "data": {
    "TransactionId": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
    "Status": "9",
    "ResponseCode": "225",
    "ResponseMessage": "Do Not Honor – CVV Verification Failed",
    "AvsResult": "Y",
    "CvvResult": "N"
  }
}
```

> **Note:** CVV filters run after the gateway authorizes the sale. A filter decline marks the transaction `declined` in AuxCORE; it does not automatically void the authorization at the processor.

---

## Testing CVV Filters

CVV results in Sandbox come from the processor's test environment, so the CVV values that trigger each result code depend on the merchant's gateway (see your processor's test documentation). Check `data.CvvResult` and `data.ResponseCode` (`225`) on the transaction response to confirm your filter.

---

## Best Practices

### ✅ DO:
- **Require CVV** for card-not-present transactions
- **Decline mismatches** (`noMatch`)
- **Combine with AVS** - Strongest fraud prevention
- **Monitor decline rates** - Adjust if needed

### ❌ DON'T:
- **Don't rely on CVV alone** - Use with AVS
- **Don't store CVV** - PCI violation
- **Don't skip testing** - Could block legitimate customers

---

## Common Scenarios

### Scenario 1: Wrong CVV Entered

**CVV Response:** `N` (no match)  
**Recommendation:** Decline, ask customer to re-enter

### Scenario 2: Issuer Doesn't Support CVV

**CVV Response:** `S` or `U`  
**Recommendation:** Leave `notProvided` / `issuerNotCertified` unselected unless your risk profile demands it

### Scenario 3: Fraudulent Transaction

Fraudster has card number but not CVV

**CVV Response:** `N` (no match)  
**Recommendation:** Decline - likely fraud

---

## PCI Compliance

⚠️ **CRITICAL:** You MUST NOT store CVV after authorization.

**Prohibited:**
- Storing CVV in databases
- Logging CVV in log files
- Including CVV in backup files
- Transmitting CVV via email

Use the [PCI hosted fields](https://vault.auxcore.net/sdk/) so card data and CVV never touch your servers.

---

## Reviewing CVV Results

There is no dedicated CVV analytics endpoint. Filter the transaction list by CVV code instead:

```http
GET /api/v1/transactions?cvvFilter=N,P
```

```bash
curl "https://uat.auxcore.net/api/v1/transactions?cvvFilter=N&dateFrom=2026-01-01&dateTo=2026-01-31" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

## Next Steps

- [Configure AVS filters →](./avs.md)
- [Risk management →](./risk.md)
- [View fraud analytics →](../receipts/transaction-reports.md)

---

**Need help?** Contact support@auxcore.net
