Skip to main content
TPSCheck Blog
Batch Processing: How to Check Thousands of Phone Numbers Against TPS

Batch Processing: How to Check Thousands of Phone Numbers Against TPS

If you have 10,000 phone numbers to check against the TPS register before a campaign launches tomorrow, you have a problem. Checking them one at a time through a web form is not a realistic option. Even if each lookup takes ten seconds, that is 28 hours of continuous, manual work.

Batch processing solves this. Instead of submitting one number at a time, you send groups of numbers in a single API request and receive all results together. What would take a day and a half of manual effort finishes in minutes.

This article explains how batch TPS checking works, walks through TPSCheck's /batch API endpoint with working code examples, and covers the practical details: rate limits, cost analysis, best practices for large datasets, and when to use batch versus single checks.

Why one-at-a-time checking does not scale

Let us put some numbers to the problem.

A typical single TPS check through an API takes around 200 milliseconds. That sounds fast until you multiply it by a real-world dataset:

Numbers to check Time at 1 per request Time with batch processing (100 per request)
1,000 ~3 minutes ~6 seconds
10,000 ~33 minutes ~1 minute
50,000 ~2.8 hours ~5 minutes
100,000 ~5.5 hours ~10 minutes

The difference is not marginal. It is the difference between a process that fits into your workflow and one that blocks everything else.

And that is just the time calculation. One-at-a-time checking also means 10,000 separate HTTP requests, 10,000 individual response handlers, and 10,000 opportunities for a network timeout or transient error to derail the process. Batch processing reduces all of that by a factor of 100.

If you are a call centre screening lists before outbound campaigns, a marketing agency managing data for multiple clients, or a CRM platform with TPS checking built into its pipeline, batch processing is not optional. It is the only approach that works at any meaningful volume. For call centre-specific guidance, see our article on TPS compliance for call centres.


What batch TPS checking is and how it works

Batch checking means sending multiple phone numbers in a single API request and receiving results for all of them in a single response.

With TPSCheck's /batch endpoint, you submit an array of phone numbers and get back:

  • TPS registration status for each number (registered or not)
  • CTPS registration status for each number
  • Phone intelligence for every number: line type (mobile or landline), original carrier, geographic location (for landlines), and country

All of this is returned in one response. One request, one response, complete results.

The numbers do not need to be in any particular format. The API accepts UK numbers with or without spaces, with or without the country code. It normalises them automatically and returns the E.164 format alongside the original input so you can match results back to your records.


TPSCheck's /batch API endpoint

The /batch endpoint accepts a POST request with an array of phone numbers and returns TPS/CTPS status plus phone intelligence for every number in the batch.

Request format

POST https://tpscheck.uk/batch
Authorization: Token your_api_key
Content-Type: application/json

{
  "phones": [
    "01564 331484",
    "01953 498974",
    "07954 844224"
  ]
}

Response format

{
  "total": 3,
  "results": [
    {
      "input": "01564 331484",
      "e164": "+441564331484",
      "valid": true,
      "tps": false,
      "ctps": false,
      "line": {
        "type": "landline",
        "original_carrier": "Virgin Media Limited",
        "location": "Lapworth",
        "country": "England",
        "prefix": "01564"
      },
      "reachability": {
        "status": "unknown",
        "confidence": "medium"
      }
    },
    {
      "input": "01953 498974",
      "e164": "+441953498974",
      "valid": true,
      "tps": true,
      "ctps": false,
      "line": {
        "type": "landline",
        "original_carrier": "AQL Wholesale Ltd",
        "location": "Attleborough",
        "country": "England",
        "prefix": "01953"
      },
      "reachability": {
        "status": "unknown",
        "confidence": "medium"
      }
    },
    {
      "input": "07954 844224",
      "e164": "+447954844224",
      "valid": true,
      "tps": false,
      "ctps": false,
      "line": {
        "type": "mobile",
        "original_carrier": "EE Limited ( TM)",
        "location": "",
        "country": "",
        "prefix": "07954"
      },
      "reachability": {
        "status": "unknown",
        "confidence": "medium"
      }
    }
  ]
}

Each result in the array includes:

  • input -- the number exactly as you submitted it
  • e164 -- the normalised international format
  • valid -- whether the number is a valid UK phone number
  • tps / ctps -- boolean registration status for each register
  • line -- phone intelligence data (type, carrier, location, country, prefix)
  • reachability -- number validity assessment

This means every batch check gives you compliance data and phone intelligence in one call. You do not need a separate service or additional API calls for line type or carrier information.

For full API documentation, see our API docs.


Code examples

Python: batch checking with chunking

This example reads a list of phone numbers, splits them into batch-sized chunks, and processes each chunk through the /batch endpoint. It handles rate limiting and collects all results.

import requests
import time

API_KEY = "your_api_key"
API_URL = "https://tpscheck.uk/batch"
BATCH_SIZE = 100  # Max numbers per request (varies by plan)

headers = {
    "Authorization": f"Token {API_KEY}",
    "Content-Type": "application/json"
}

def check_batch(phones):
    """Send a batch of phone numbers for TPS/CTPS checking."""
    response = requests.post(
        API_URL,
        headers=headers,
        json={"phones": phones}
    )

    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 5))
        print(f"Rate limited. Waiting {retry_after} seconds...")
        time.sleep(retry_after)
        return check_batch(phones)

    response.raise_for_status()
    return response.json()

def chunk_list(items, size):
    """Split a list into chunks of the given size."""
    for i in range(0, len(items), size):
        yield items[i:i + size]

with open("phone_numbers.txt", "r") as f:
    all_numbers = [line.strip() for line in f if line.strip()]

print(f"Checking {len(all_numbers)} numbers in batches of {BATCH_SIZE}...")

all_results = []
tps_registered = []

for i, batch in enumerate(chunk_list(all_numbers, BATCH_SIZE)):
    print(f"Processing batch {i + 1} ({len(batch)} numbers)...")

    data = check_batch(batch)
    results = data.get("results", [])
    all_results.extend(results)

    for result in results:
        if result.get("tps") or result.get("ctps"):
            tps_registered.append(result["input"])

    time.sleep(1)

print(f"\nComplete. {len(all_results)} numbers checked.")
print(f"TPS/CTPS registered: {len(tps_registered)}")
print(f"Safe to call: {len(all_results) - len(tps_registered)}")

cURL: single batch request

For quick testing or shell script integration:

curl --request POST \
  --url https://tpscheck.uk/batch \
  --header 'Authorization: Token your_api_key' \
  --header 'Content-Type: application/json' \
  --data '{
    "phones": [
      "01234 567890",
      "07700 900123",
      "0161 496 0000",
      "02079 460123",
      "07911 123456"
    ]
  }'

JavaScript (Node.js): batch checking with async/await

const API_KEY = "your_api_key";
const API_URL = "https://tpscheck.uk/batch";
const BATCH_SIZE = 100;

async function checkBatch(phones) {
  const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Authorization": `Token ${API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ phones })
  });

  if (response.status === 429) {
    const retryAfter = parseInt(response.headers.get("Retry-After") || "5");
    console.log(`Rate limited. Waiting ${retryAfter} seconds...`);
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    return checkBatch(phones);
  }

  if (!response.ok) {
    throw new Error(`API error: ${response.status} ${response.statusText}`);
  }

  return response.json();
}

function chunkArray(array, size) {
  const chunks = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}

async function processNumbers(phoneNumbers) {
  const chunks = chunkArray(phoneNumbers, BATCH_SIZE);
  const allResults = [];

  for (let i = 0; i < chunks.length; i++) {
    console.log(`Processing batch ${i + 1} of ${chunks.length}...`);

    const data = await checkBatch(chunks[i]);
    allResults.push(...data.results);

    // Pause between batches
    if (i < chunks.length - 1) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  const tpsRegistered = allResults.filter(r => r.tps || r.ctps);
  const safeToDial = allResults.filter(r => !r.tps && !r.ctps && r.valid);

  console.log(`\nTotal checked: ${allResults.length}`);
  console.log(`TPS/CTPS registered: ${tpsRegistered.length}`);
  console.log(`Safe to call: ${safeToDial.length}`);

  return allResults;
}

// Example usage
const numbers = [
  "01234 567890",
  "07700 900123",
  "0161 496 0000"
  // ... load from your database or file
];

processNumbers(numbers);

All examples above use the real TPSCheck API format. Replace your_api_key with the token from your TPSCheck dashboard. For the complete API reference, see our documentation.


Best practices for batch processing

Chunk large lists into batch-sized requests

The /batch endpoint accepts up to 50 numbers per request on the Starter plan and up to 100 numbers per request on Pro and above. If you have 10,000 numbers to check, you need to split them into appropriately sized chunks.

The Python and JavaScript examples above demonstrate this pattern. The key is to iterate through your list systematically, submitting one batch at a time, and collecting results as you go.

Respect rate limits

Every TPSCheck plan has a per-minute request limit. Exceeding it returns a 429 Too Many Requests response with a Retry-After header indicating how long to wait.

The response also includes rate limit headers on every request:

  • X-RateLimit-Limit -- your plan's maximum requests per minute
  • X-RateLimit-Remaining -- requests remaining in the current window
  • X-RateLimit-Reset -- when the window resets

Good practice is to monitor X-RateLimit-Remaining and slow down before you hit the limit, rather than running at full speed and handling 429 responses reactively.

Implement retry logic

Network issues, temporary server errors, and rate limiting can all interrupt batch processing. Your code should handle:

  • 429 responses -- wait for the duration specified in Retry-After, then retry
  • 5xx responses -- wait briefly and retry with exponential backoff (1 second, 2 seconds, 4 seconds)
  • Timeouts -- retry the specific batch that failed, not the entire job

The code examples above include basic retry logic for rate limiting. For production systems, add retry handling for server errors and network timeouts as well.

Store and act on results

Do not just check numbers and discard the results. For each number, store:

  • The TPS and CTPS status returned
  • The timestamp of when the check was performed
  • The phone intelligence data (line type, carrier, location)

This serves two purposes. First, it gives you an audit trail demonstrating that you screened your lists before calling, which is what the ICO requires. Second, it means you do not need to re-check the same numbers unnecessarily. A result is valid for up to 28 days under ICO guidance. For a full explanation of the 28-day rule, see our article on the 28-day TPS re-check rule explained.


Rate limits by plan

Each TPSCheck plan has different rate limits and batch sizes. These determine how quickly you can process large datasets.

Plan Requests/min Batch size Max numbers/min Time to check 10,000
Starter 60 50 3,000 ~4 min
Pro 120 100 12,000 ~1 min
Growth 300 100 30,000 ~20 sec
Business 600 100 60,000 ~10 sec
Enterprise Custom Custom Custom Custom

A few points to note:

  • Free and PAYG plans do not include batch checking. You need a Starter plan or above to use the /batch endpoint.
  • Each batch request counts as one request against your rate limit, regardless of how many numbers are in it. A batch of 100 numbers counts the same as a batch of 1.
  • Enterprise plans can be configured with custom rate limits and batch sizes for organisations processing very high volumes.

For full plan details and rate limit documentation, see our pricing page.


Cost analysis: what it costs to check at volume

One of the most common questions about batch processing is cost. Here is a breakdown of what it costs to check different volumes on each plan.

Subscription plans

Volume Starter (£29/mo) Pro (£79/mo) Growth (£149/mo) Business (£199/mo)
10,000 £29 (10K included) £79 £149 £199
50,000 5 months at £29 = £145 £79 (50K included) £149 £199
100,000 Not practical 2 months at £79 = £158 £149 (150K included) £199
500,000 Not practical Not practical 4 months at £149 = £596 £199 (500K included)

Effective cost per 1,000 checks

Plan Monthly price Checks included Cost per 1,000
Starter £29 10,000 £2.90
Pro £79 50,000 £1.58
Growth £149 150,000 £0.99
Business £199 500,000 £0.40
PAYG (Small pack) One-off 1,000 £4.00
PAYG (Large pack) One-off 25,000 £2.00
PAYG (XL pack) One-off 100,000 £1.50

The pattern is clear: per-check costs drop significantly as volume increases. If you are regularly checking tens of thousands of numbers, a subscription plan is substantially cheaper than pay-as-you-go credits, and it gives you access to batch checking, audit logs, and compliance features that PAYG does not include.

All subscription plans also offer a 17% discount with annual billing. That brings the Business plan down to £165 per month effective, making the cost per 1,000 checks just £0.33 at full utilisation.

For the full pricing breakdown, see our pricing page.


When to use batch vs. single checks

Batch and single checks serve different purposes. Choosing the right one depends on your workflow.

Use batch checking for:

  • Pre-campaign screening. Before launching any outbound calling campaign, run your entire target list through batch checking. This is the primary use case. Screen the list, remove TPS-registered numbers, and proceed with confidence.
  • CRM database cleansing. Periodically clean your entire contact database against TPS and CTPS. Batch processing makes it practical to re-screen tens of thousands of records on a regular schedule.
  • 28-day re-checks. ICO guidance requires re-screening within 28 days. Batch checking lets you process your active lists efficiently on a rolling basis without disrupting operations.
  • New data imports. When you receive a new list of leads or contacts, batch check the entire set before adding them to your calling queue.

For agencies managing multiple client lists, batch checking is essential for maintaining compliance across accounts. See our article on how agencies manage TPS compliance for multiple clients.

Use single checks for:

  • Real-time dialler integration. When your predictive dialler or CRM triggers an outbound call, a single /check request verifies the number in real time before the call connects.
  • Inbound lead processing. When a new lead arrives via web form, check the number immediately as part of your lead intake workflow.
  • Manual lookups. Agents or managers checking individual numbers through a dashboard or internal tool.

The single /check endpoint is documented in detail in our API documentation.

Many businesses use both. Batch checking handles the bulk screening before campaigns, while single checks provide real-time verification at the point of dialling. The two approaches complement each other.


Compliance considerations

Batch checking is a tool. Compliance is a process. Here are the regulatory points to keep in mind when processing large volumes.

The 28-day re-check requirement

ICO guidance states that you should re-screen calling lists against TPS and CTPS within 28 days before making marketing calls. For large databases, batch checking makes this practical. Schedule automated re-checks at 25-day intervals to provide a buffer, and you will never fall outside the compliance window.

For a detailed explanation of where this requirement comes from and how it works, see the 28-day TPS re-check rule explained.

Maintain audit trails

Every batch check through TPSCheck is logged with a timestamp, the numbers checked, and the results returned. On Pro plans and above, these logs are retained (90 days to 24 months depending on plan) and can be exported as CSV or PDF for compliance evidence.

If the ICO ever asks for proof that you screened your lists before calling, these audit records are your evidence. Keeping them is not optional. For more on what the ICO expects, see our article on TPS fines and ICO enforcement.

Act on the results

Checking numbers is only half the job. You must remove or suppress TPS-registered numbers from your calling list and document that you did so. A batch check that identifies 400 TPS-registered numbers out of 10,000 is worthless if those 400 numbers are still dialled.

Store results with timestamps

Record when each number was checked and what the result was. This serves as both your compliance evidence and your trigger for when re-checking is due.


Getting started with batch checking

Batch checking is available on all paid subscription plans starting at £29 per month for the Starter plan.

Here is how to start:

  1. Create a free account at tpscheck.uk/subscribe. No credit card required. The free plan gives you 50 single checks per month to explore the API.

  2. Get your API key from the dashboard. This is the token you will use for authentication.

  3. Upgrade to a paid plan to unlock the /batch endpoint. Starter (£29/month) includes 10,000 checks with batches of up to 50 numbers per request. Pro (£79/month) includes 50,000 checks with batches of up to 100.

  4. Make your first batch request using the code examples above or the API documentation.

  5. Process the results. Separate your numbers into safe-to-call and TPS-registered lists. Suppress the registered numbers. Store the results with timestamps.

If you are evaluating TPSCheck against other providers, our comparison of UK TPS check APIs covers features, pricing, and the honest trade-offs across the market.


Summary

Batch processing transforms TPS compliance from a time-consuming bottleneck into a fast, automated step in your campaign workflow. Instead of hours of manual checking, you screen thousands of numbers in minutes. Every check returns TPS status, CTPS status, and phone intelligence data in a single response.

TPSCheck's /batch endpoint is designed for exactly this workflow. Submit your numbers, receive complete results, act on them. The API handles normalisation, returns structured JSON, and logs everything for your compliance records.

The cost is modest. Checking 10,000 numbers on a Starter plan costs £29 per month. At Business plan volumes, the effective cost drops to 40p per 1,000 checks. Compare that to the minimum ICO fine of £40,000 for calling TPS-registered numbers, and the calculation makes itself.

Start your free account today. Get 50 checks to explore the API, then upgrade to unlock batch processing and start screening your lists at scale.

Create your free account | Read the API documentation | View the product guide


TPSCheck is an independent commercial service operated by Visian Systems Limited. It is not affiliated with, endorsed by, or operated by the Information Commissioner's Office (ICO), TPS Limited, or the Data & Marketing Association (DMA).