# AVS Filters

Configure Address Verification Service (AVS) filters to prevent fraudulent transactions.

---

## Overview

AVS (Address Verification Service) compares the billing address provided by the customer with the address on file at the card issuer. Use AVS filters to:

- 🛡️ **Prevent fraud** - Decline approved sales whose AVS result you do not accept
- ✅ **Accept/decline** based on AVS response categories
- ⚙️ **Two layers** - A merchant-wide filter (Fraud Prevention settings) and per-gateway rules (Gateways tab)

AVS filtering is applied **after** the gateway approves a card sale. If a filter rejects the AVS result, the transaction is recorded as `declined` with response code `220` and response text `Do Not Honor – Address Verification Failed`. Filters only apply to card payments (not ACH, cash, etc.).

---

## Get AVS 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"],
    "rejectOnUnavailable": false,
    "rejectOnError": false,
    "rejectOnNoMatch": true,
    "rejectOnPartialMatch": false
  }
}
```

If the merchant has never saved settings, the defaults above are returned with empty `avsRejectCodes` / `cvvRejectCodes`.

| Status | When |
|--------|------|
| `200` | Settings (or defaults) returned |
| `404` | `NOT_FOUND` — merchant not found in your tenant |

---

## Update AVS Settings

### Endpoint

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

Requires the `business.manage` permission. The body **replaces** the whole settings object — omitted fields reset to their defaults, so always send both `avsRejectCodes` and `cvvRejectCodes`.

```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", "partialMatch"],
    "cvvRejectCodes": ["noMatch"]
  }'
```

**Request body:**

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `enabled` | boolean | `true` | Turns the merchant-level AVS and CVV filters on/off |
| `avsRejectCodes` | string[] | `[]` | AVS categories to decline (see below) |
| `cvvRejectCodes` | string[] | `[]` | CVV categories to decline (see [CVV Filters](./cvv.md)) |
| `rejectOnUnavailable` | boolean | `false` | Stored with the settings; the decline decision is driven by the reject-code lists |
| `rejectOnError` | boolean | `false` | Stored with the settings; the decline decision is driven by the reject-code lists |
| `rejectOnNoMatch` | boolean | `true` | Stored with the settings; the decline decision is driven by the reject-code lists |
| `rejectOnPartialMatch` | boolean | `false` | Stored with the settings; the decline decision is driven by the reject-code lists |

**Response:**
```json
{
  "success": true,
  "data": {
    "enabled": true,
    "avsRejectCodes": ["noMatch", "partialMatch"],
    "cvvRejectCodes": ["noMatch"],
    "rejectOnUnavailable": false,
    "rejectOnError": false,
    "rejectOnNoMatch": true,
    "rejectOnPartialMatch": false
  },
  "message": "Fraud prevention settings updated successfully"
}
```

| Status | When |
|--------|------|
| `200` | Saved |
| `403` | Caller lacks `business.manage` |
| `404` | `NOT_FOUND` — merchant not found in your tenant |

> **Note:** The body is not validated — unknown category keys are saved but ignored. After saving, the settings are synced to the card-security service in the background, and that synced copy is what transactions are checked against. A sync failure is logged and does not fail the request, so a `200` here does not guarantee the new filter is live. If the card-security lookup fails at payment time, the filter fails open (the sale stays approved).

---

## AVS Reject Categories

`avsRejectCodes` takes category keys, not raw AVS letters. Each key maps to these gateway AVS codes:

| Key | AVS codes declined | Meaning |
|-----|--------------------|---------|
| `noMatch` | `N` | Neither street address nor ZIP match |
| `partialMatch` | `A`, `W`, `Z` | Only the address or only the ZIP matches |
| `unavailable` | `U`, `B`, `G` | Address information unavailable / non-US issuer |
| `notSupported` | `S`, `R`, `E` | Service not supported, retry/system unavailable, or error |

The filter is stored as an allow-list of the eleven letters in the table below minus the ones you reject. `Y` (full match) is never declined. If `avsRejectCodes` is empty (or `enabled` is `false`), AVS never declines. Once at least one key is selected, any code **outside** those eleven letters (for example `X`, `D` or `M`, which some processors return) is also declined. The merchant-level filter only runs when the gateway returned an AVS code.

### AVS Response Codes

| Code | Address | ZIP | Description |
|------|---------|-----|-------------|
| **Y** | ✅ Match | ✅ Match | Full match |
| **A** | ✅ Match | ❌ No match | Address match only |
| **W** | ❌ No match | ✅ Match (9-digit) | ZIP match only |
| **Z** | ❌ No match | ✅ Match (5-digit) | ZIP match only |
| **N** | ❌ No match | ❌ No match | No match |
| **U** | ❓ Unknown | ❓ Unknown | Information unavailable |
| **B** | ❓ | ❓ | Address information not verified (international) |
| **G** | N/A | N/A | Non-US card issuer |
| **R** | N/A | N/A | Retry / system unavailable |
| **S** | N/A | N/A | Service not supported |
| **E** | N/A | N/A | Error / invalid AVS data |

---

## Per-Gateway AVS Rules

Each processor account a merchant has (Gateways tab) can carry its own AVS rules. These are evaluated **first**, against the gateway that actually processed the sale (failover-aware); the merchant-level filter above then runs only if the sale is still approved.

Set them on the merchant gateway record:

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

```json
{
  "requireAVS": true,
  "avsRules": {
    "rejectOnMismatch": true,
    "allowedResponses": ["Y", "A", "Z"]
  }
}
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `requireAVS` | boolean | `false` | Decline a card sale when the gateway returns **no** AVS result |
| `avsRules.rejectOnMismatch` | boolean | — | When `true`, any AVS code not in `allowedResponses` declines |
| `avsRules.allowedResponses` | string[] | — | Accepted AVS letters (case-insensitive) |

If `rejectOnMismatch` is not `true`, the per-gateway AVS rule never declines.

---

## Preset Configurations

### Strict (High Security)

Decline anything that is not a full match:

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

### Balanced (Recommended)

Decline only complete mismatches:

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

### Off

Never decline on AVS:

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

---

## Transaction Response

The public transaction response returns the gateway's AVS code in `data.AvsResult`:

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

### Declined by AVS

Returned with HTTP `402`:

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

When a per-gateway `requireAVS` rule declines because no AVS result came back, the response text is `Do Not Honor – Address Verification Required`.

> **Note:** AVS is evaluated 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 AVS Filters

AVS results in Sandbox come from the processor's own test environment, so the address/ZIP values that trigger each code depend on the gateway configured for the merchant (see your processor's test documentation). Verify your filter by checking `data.AvsResult` and `data.ResponseCode` (`220`) on the transaction response.

```bash
curl -X POST https://uat.auxcore.net/api/v1/public/transaction \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Amount": 10.00,
    "SuggestedMode": "Card",
    "pciToken": "pci_tok_8f2c1a9b7e4d",
    "BillingAddress": "123 Main Street",
    "BillingPostalCode": "10001"
  }'
```

Raw `CardNumber` / `CVV` is rejected on Sandbox and Production (`400 PCI_SCOPE_VIOLATION`); collect the card with the PCI SDK and send its `pciToken`.

---

## Best Practices

### ✅ DO:
- **Start with balanced settings** - Too strict reduces conversion
- **Leave `unavailable` / `notSupported` unselected** for international traffic - many non-US issuers don't support AVS
- **Test in Sandbox first** - Ensure settings work with your processor
- **Monitor decline rates** - Adjust if too many legitimate declines
- **Combine with CVV** - Use both for stronger fraud prevention

### ❌ DON'T:
- **Don't decline everything** - Legitimate transactions may have minor mismatches
- **Don't rely on AVS alone** - Use as part of comprehensive fraud strategy
- **Don't change frequently** - Causes inconsistent customer experience

---

## Common Scenarios

### Scenario 1: Address Typo

Customer enters "123 Main Street" but card on file shows "124 Main St"

**AVS Response:** `Z` (ZIP match only)  
**Recommendation:** Accept — leave `partialMatch` unselected

### Scenario 2: Recently Moved

Customer moved but hasn't updated address with bank

**AVS Response:** `N` (no match)  
**Recommendation:** Decline (`noMatch`) or contact customer

### Scenario 3: International Card

Customer using non-US card

**AVS Response:** `G` (non-US issuer)  
**Recommendation:** Leave `unavailable` unselected, use other fraud signals

---

## Reviewing AVS Results

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

```http
GET /api/v1/transactions?avsFilter=N,A,Z
```

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

`avsFilter` (and `cvvFilter`) take a comma-separated list of raw response codes.

---

## Next Steps

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

---

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