ScamVerify™

Batch Processing

Submit up to 100 phone numbers or URLs in a single request using the ScamVerify™ batch API endpoints.

The ScamVerify™ API supports batch processing for phone lookups and URL verifications. Instead of making individual API calls, you can submit up to 100 items in a single request and receive all results at once.

Batch Endpoints

EndpointMethodDescription
/api/v1/batch/phonePOSTBatch phone number lookup
/api/v1/batch/urlPOSTBatch URL verification

Batch endpoints are fixed at 5 RPM for all tiers. Since each batch can contain up to 100 items, this allows up to 500 lookups per minute even at the batch rate limit.

Request Format

Submit an array of items in the request body. Each item is processed independently.

curl -X POST https://scamverify.ai/api/v1/batch/phone \
  -H "Authorization: Bearer sv_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "phone_number": "+12025551234" },
      { "phone_number": "+13105559876" },
      { "phone_number": "+14155550123" }
    ]
  }'

Limits

  • Maximum 100 items per batch request
  • 10 concurrent lookups are processed internally for faster throughput
  • Each item that is not already cached consumes 1 quota from the relevant channel

Response Format

The response includes individual results for each item, plus a summary:

{
  "results": [
    {
      "input": "+12025551234",
      "risk_score": 82,
      "verdict": "high_risk",
      "explanation": "This number has 14 FTC complaints...",
      "cached": false,
      "cache_expires_at": "2026-03-10T14:30:00Z"
    },
    {
      "input": "+13105559876",
      "risk_score": 15,
      "verdict": "low_risk",
      "explanation": "No complaints found...",
      "cached": true,
      "cache_expires_at": "2026-03-10T08:15:00Z"
    },
    {
      "input": "+14155550123",
      "error": {
        "code": "validation_error",
        "message": "Invalid phone number format"
      }
    }
  ],
  "summary": {
    "total": 3,
    "succeeded": 2,
    "failed": 1,
    "high_risk": 1,
    "medium_risk": 0,
    "low_risk": 1
  },
  "quota_used": 1
}

Result Fields

Each item in the results array contains either a successful lookup result or an error object. Successful results have the same fields as individual lookup responses (risk_score, verdict, explanation, cached, cache_expires_at, and channel-specific signals). Failed items include an error object with code and message.

Summary Fields

FieldDescription
totalTotal number of items submitted
succeededNumber of items that returned a result
failedNumber of items that returned an error
high_riskItems with verdict high_risk
medium_riskItems with verdict medium_risk
low_riskItems with verdict low_risk

Quota Usage

The quota_used field shows how many quota units were consumed by the batch. Cached results do not consume quota, so quota_used may be less than succeeded.

Partial Quota Exhaustion

If your quota runs out mid-batch, the items already processed will return results, and the remaining items will return error objects:

{
  "results": [
    { "input": "+12025551234", "risk_score": 82, "verdict": "high_risk", "..." : "..." },
    { "input": "+13105559876", "risk_score": 15, "verdict": "low_risk", "..." : "..." },
    {
      "input": "+14155550123",
      "error": {
        "code": "quota_exhausted",
        "message": "Phone lookup quota exhausted mid-batch"
      }
    }
  ],
  "summary": { "total": 3, "succeeded": 2, "failed": 1, "..." : "..." },
  "quota_used": 2
}

When quota exhaustion occurs mid-batch, the order of processing is not guaranteed. Some items may succeed while others fail, regardless of their position in the input array.

Code Examples

import requests

API_KEY = "sv_live_abc123..."
BASE_URL = "https://scamverify.ai/api/v1"

# Batch phone lookup
phone_numbers = [
    "+12025551234",
    "+13105559876",
    "+14155550123",
    "+16505551111",
    "+17185552222",
]

response = requests.post(
    f"{BASE_URL}/batch/phone",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={
        "items": [{"phone_number": num} for num in phone_numbers]
    },
)

data = response.json()

# Process results
for result in data["results"]:
    if "error" in result:
        print(f"{result['input']}: ERROR - {result['error']['message']}")
    else:
        print(f"{result['input']}: {result['verdict']} (score: {result['risk_score']})")

# Check summary
summary = data["summary"]
print(f"\n{summary['succeeded']}/{summary['total']} succeeded, "
      f"{summary['high_risk']} high risk, "
      f"{data['quota_used']} quota used")
const API_KEY = "sv_live_abc123...";
const BASE_URL = "https://scamverify.ai/api/v1";

// Batch phone lookup
const phoneNumbers = [
  "+12025551234",
  "+13105559876",
  "+14155550123",
  "+16505551111",
  "+17185552222",
];

const response = await fetch(`${BASE_URL}/batch/phone`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    items: phoneNumbers.map((num) => ({ phone_number: num })),
  }),
});

const data = await response.json();

// Process results
for (const result of data.results) {
  if (result.error) {
    console.log(`${result.input}: ERROR - ${result.error.message}`);
  } else {
    console.log(`${result.input}: ${result.verdict} (score: ${result.risk_score})`);
  }
}

// Check summary
const { summary, quota_used } = data;
console.log(
  `\n${summary.succeeded}/${summary.total} succeeded, ` +
  `${summary.high_risk} high risk, ` +
  `${quota_used} quota used`
);

When to Use Batch vs Individual Lookups

Use batch when:

  • You have a list of numbers or URLs to check (CSV import, database scan, etc.)
  • You want to minimize the number of HTTP connections
  • You need a summary of risk distribution across a set of items

Use individual lookups when:

  • You need real-time results for a single item (user-facing search)
  • You want to process items as they arrive rather than collecting them first
  • You need the fastest possible response time for each item

Chunking Large Lists

If you have more than 100 items, split them into chunks and send multiple batch requests. Remember to respect the 5 RPM batch rate limit.

import time

def batch_lookup_all(phone_numbers, api_key, chunk_size=100):
    results = []
    chunks = [phone_numbers[i:i + chunk_size] for i in range(0, len(phone_numbers), chunk_size)]

    for i, chunk in enumerate(chunks):
        if i > 0:
            time.sleep(12)  # Stay within 5 RPM limit

        response = requests.post(
            f"{BASE_URL}/batch/phone",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json",
            },
            json={"items": [{"phone_number": num} for num in chunk]},
        )
        data = response.json()
        results.extend(data["results"])

    return results

On this page