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

# Batch UPI Verification: Screen Up to 100 VPAs at Once

> Submit up to 100 UPI VPAs in one API call for overnight watchlist refreshes, pre-settlement reconciliation, and bulk beneficiary screening.

When you need to screen dozens or thousands of UPI VPAs at once — overnight watchlist refreshes, pre-settlement reconciliation, or bulk beneficiary uploads — making individual API calls for each VPA is impractical. The FraudTrace batch endpoint lets you submit up to 100 VPAs in a single request and receive a structured array of results in one response, dramatically reducing integration complexity and round-trip overhead.

## When to use batch lookup

| Use case                        | Description                                                                              |
| ------------------------------- | ---------------------------------------------------------------------------------------- |
| **Reconciliation runs**         | Screen all outgoing UPI payouts before a settlement window closes                        |
| **Overnight watchlist refresh** | Re-screen your full beneficiary or merchant portfolio against the latest FraudTrace data |
| **Onboarding queues**           | Process a backlog of pending merchant or customer VPAs in one go                         |
| **Bulk beneficiary screening**  | Validate imported beneficiary lists before activating them for payments                  |

## Request format

Send a `POST` request to `/v1/verify/upi/batch` with a JSON body containing a `upis` array:

```json theme={null}
{
  "upis": ["user1@ybl", "user2@okaxis", "merchant3@paytm"]
}
```

<Note>
  The batch endpoint accepts a maximum of **100 UPIs per request**. If your
  list exceeds 100 VPAs, split it into chunks of 100 and send separate
  requests. See the Python example below for a chunking implementation.
</Note>

## Response format

The API returns an array of result objects. Each object follows the same schema as the single VPA lookup — `FLAGGED` entries include confidence, cluster, and source details; `CLEARED` entries return minimal fields.

```json theme={null}
[
  {
    "upi": "user1@ybl",
    "status": "FLAGGED",
    "confidence": 0.94,
    "risk_category": "mule",
    "cluster_id": "MC-2104",
    "cluster_size": 7,
    "first_seen": "2025-11-14T08:22:00Z",
    "last_seen": "2026-04-01T16:45:00Z",
    "sources": [
      {
        "url": "https://bet-quick-in.com",
        "category": "gambling",
        "captured_at": "2025-12-01T10:00:00Z",
        "screenshot_available": true
      }
    ],
    "evidence_count": 3
  },
  {
    "upi": "user2@okaxis",
    "status": "CLEARED",
    "confidence": null,
    "cluster_id": null,
    "sources": [],
    "evidence_count": 0
  },
  {
    "upi": "merchant3@paytm",
    "status": "CLEARED",
    "confidence": null,
    "cluster_id": null,
    "sources": [],
    "evidence_count": 0
  }
]
```

The results array preserves the same order as your input `upis` array, making it easy to zip results back to your original records.

## Complete examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.fraudtraceai.com/v1/verify/upi/batch \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "upis": ["user1@ybl", "user2@okaxis", "merchant3@paytm"]
    }'
  ```

  ```python Python theme={null}
  import requests
  import time

  API_KEY = "YOUR_API_KEY"
  BASE_URL = "https://api.fraudtraceai.com"

  def batch_screen(vpas: list[str], chunk_size: int = 100) -> list[dict]:
      """Screen a list of VPAs in chunks of up to 100, with backoff on rate limits."""
      all_results = []

      for i in range(0, len(vpas), chunk_size):
          chunk = vpas[i : i + chunk_size]
          retries = 0

          while True:
              resp = requests.post(
                  f"{BASE_URL}/v1/verify/upi/batch",
                  json={"upis": chunk},
                  headers={"Authorization": f"Bearer {API_KEY}"},
              )

              if resp.status_code == 429:
                  wait = 2 ** retries
                  print(f"Rate limited. Retrying in {wait}s...")
                  time.sleep(wait)
                  retries += 1
                  continue

              resp.raise_for_status()
              all_results.extend(resp.json())
              break

      return all_results


  def split_results(results: list[dict]) -> tuple[list[dict], list[dict]]:
      """Separate FLAGGED from CLEARED results."""
      flagged = [r for r in results if r["status"] == "FLAGGED"]
      cleared = [r for r in results if r["status"] == "CLEARED"]
      return flagged, cleared


  # Example usage
  vpa_list = ["user1@ybl", "user2@okaxis", "merchant3@paytm"]
  results = batch_screen(vpa_list)

  flagged, cleared = split_results(results)

  print(f"Screened {len(results)} VPAs")
  print(f"  FLAGGED : {len(flagged)}")
  print(f"  CLEARED : {len(cleared)}")

  for item in flagged:
      print(
          f"  ⚠ {item['upi']} — confidence {item['confidence']:.2f}, "
          f"cluster {item['cluster_id']}, risk: {item['risk_category']}"
      )
  ```
</CodeGroup>

## Rate limits

Rate limits apply per API key across all endpoints. If you exceed your limit, the API returns `HTTP 429 Too Many Requests`.

<Tip>
  For very large VPA lists, process in chunks of 100 and implement exponential
  backoff when you receive a `429` response — start with a 2-second wait and
  double on each retry. The Python example above demonstrates this pattern.
  Contact [support@fraudtraceai.com](mailto:support@fraudtraceai.com) if you
  need higher throughput limits for your use case.
</Tip>

## Processing results

After splitting results into `FLAGGED` and `CLEARED` lists, apply the same confidence-based action logic you use for single lookups:

| Status    | Confidence | Action                        |
| --------- | ---------- | ----------------------------- |
| `CLEARED` | —          | Allow / no action required    |
| `FLAGGED` | 0.85–1.0   | Block; escalate to fraud team |
| `FLAGGED` | 0.60–0.84  | Queue for manual review       |
| `FLAGGED` | 0.0–0.59   | Flag for monitoring           |

For any `FLAGGED` result with a `cluster_id`, you can retrieve the full cluster — including all associated VPAs — using the cluster endpoint:

```bash theme={null}
GET https://api.fraudtraceai.com/v1/verify/upi/cluster/{cluster_id}
```

See [Interpreting Results](/guides/interpreting-results) for a detailed explanation of every field in the response.
