DEV Community

Cover image for Python API Tutorial: Your First APIVerve Call
APIVerve
APIVerve

Posted on • Originally published at blog.apiverve.com

Python API Tutorial: Your First APIVerve Call

Every tutorial on this blog has been JavaScript.

That's fine if you're a JavaScript developer. But if you're coming from the Python world—data science, backend services, automation scripts—you've been reading code examples in a language that isn't yours and mentally translating.

Let's fix that.

The Simplest Possible Call

import requests

response = requests.get(
    'https://api.apiverve.com/v1/randomquote',
    headers={'x-api-key': 'YOUR_API_KEY'}
)

data = response.json()
print(data['data']['quote'])
# "The only way to do great work is to love what you do."
Enter fullscreen mode Exit fullscreen mode

That's it. Import requests, make the call, get the data. If you've used the requests library before (and you probably have), this is nothing new.

If You Don't Have Requests

pip install requests
Enter fullscreen mode Exit fullscreen mode

You probably already have it. It's included with most Python distributions and is a dependency of basically everything. But if you're in a fresh environment, now you've got it.

Understanding the Response

Every APIVerve endpoint returns the same structure:

{
    "status": "ok",         # or "error"
    "error": None,          # error message if status is "error"
    "data": {
        # The actual response data
    }
}
Enter fullscreen mode Exit fullscreen mode

This matters because you should always check the status before trusting the data:

response = requests.get(url, headers=headers)
result = response.json()

if result['status'] != 'ok':
    print(f"Error: {result['error']}")
    return None

return result['data']
Enter fullscreen mode Exit fullscreen mode

Consistent error handling across 300+ APIs. No guessing what each one returns on failure.

A Real Example: Email Validation

Let's build something practical. Email validation is one of the most common API use cases:

import requests
import os

def validate_email(email):
    response = requests.get(
        'https://api.apiverve.com/v1/emailvalidator',
        headers={'x-api-key': os.environ.get('APIVERVE_KEY')},
        params={'email': email}
    )

    data = response.json()

    if data['status'] != 'ok':
        return {'valid': False, 'error': data['error']}

    result = data['data']
    return {
        'valid': result['isValid'],
        'is_company': result['isCompanyEmail'],
        'is_free': result['isFreeEmail'],
        'domain': result['domain']
    }

# Usage
result = validate_email('test@example.com')
print(f"Valid: {result['valid']}, Company email: {result['is_company']}")
Enter fullscreen mode Exit fullscreen mode

Notice a few things:

  1. API key from environment — Never hardcode credentials. Use os.environ.get().
  2. params dict — Requests handles URL encoding automatically. No need for manual string formatting.
  3. Clean return value — Transform the API response into what your code actually needs.

Setting Up Your Environment

Before you can use os.environ.get('APIVERVE_KEY'), you need to set the variable.

In your terminal:

export APIVERVE_KEY=your_api_key_here
Enter fullscreen mode Exit fullscreen mode

In a .env file (with python-dotenv):

# .env
APIVERVE_KEY=your_api_key_here
Enter fullscreen mode Exit fullscreen mode
from dotenv import load_dotenv
load_dotenv()

# Now os.environ.get('APIVERVE_KEY') works
Enter fullscreen mode Exit fullscreen mode

In your IDE:
Most IDEs (PyCharm, VS Code) let you set environment variables in run configurations. This keeps secrets out of your code.

Building a Reusable Client

If you're making multiple API calls, wrap them in a class:

import requests
import os

class APIVerveClient:
    BASE_URL = 'https://api.apiverve.com/v1'

    def __init__(self, api_key=None):
        self.api_key = api_key or os.environ.get('APIVERVE_KEY')
        if not self.api_key:
            raise ValueError("API key required. Set APIVERVE_KEY env var or pass api_key parameter.")

        self.session = requests.Session()
        self.session.headers.update({'x-api-key': self.api_key})

    def _request(self, endpoint, params=None):
        """Make a request and return the data, or raise on error."""
        response = self.session.get(
            f"{self.BASE_URL}/{endpoint}",
            params=params or {},
            timeout=30
        )

        response.raise_for_status()
        result = response.json()

        if result['status'] != 'ok':
            raise Exception(result.get('error', 'Unknown error'))

        return result['data']

    def validate_email(self, email):
        return self._request('emailvalidator', {'email': email})

    def lookup_ip(self, ip):
        return self._request('iplookup', {'ip': ip})

    def get_quote(self):
        return self._request('randomquote')

    def convert_currency(self, value, from_currency, to_currency):
        return self._request('currencyconverter', {
            'value': value,
            'from': from_currency,
            'to': to_currency
        })
Enter fullscreen mode Exit fullscreen mode

Now calling any API is one line:

client = APIVerveClient()

# Email validation
email = client.validate_email('john@acme.com')
print(f"Valid: {email['isValid']}, Company: {email['isCompanyEmail']}")

# IP geolocation
location = client.lookup_ip('8.8.8.8')
print(f"Location: {location['city']}, {location['country']}")

# Random quote
quote = client.get_quote()
print(f'"{quote["quote"]}"{quote["author"]}')

# Currency conversion
converted = client.convert_currency(100, 'USD', 'EUR')
print(f"$100 = €{converted['convertedValue']}")
Enter fullscreen mode Exit fullscreen mode

The session object reuses connections, so multiple calls are faster than creating new connections each time.

Error Handling That Doesn't Suck

Production code needs to handle failures gracefully:

import requests
from requests.exceptions import Timeout, ConnectionError, HTTPError

class APIVerveClient:
    # ... previous code ...

    def _request(self, endpoint, params=None, retries=3):
        """Make a request with retry logic."""
        last_error = None

        for attempt in range(retries):
            try:
                response = self.session.get(
                    f"{self.BASE_URL}/{endpoint}",
                    params=params or {},
                    timeout=30
                )

                response.raise_for_status()
                result = response.json()

                if result['status'] != 'ok':
                    raise Exception(result.get('error', 'Unknown error'))

                return result['data']

            except Timeout:
                last_error = "Request timed out"
            except ConnectionError:
                last_error = "Could not connect to API"
            except HTTPError as e:
                if e.response.status_code == 401:
                    raise Exception("Invalid API key")
                if e.response.status_code == 429:
                    # Rate limited - wait and retry
                    import time
                    time.sleep(2 ** attempt)
                    continue
                last_error = f"HTTP error: {e.response.status_code}"
            except Exception as e:
                last_error = str(e)

        raise Exception(f"Request failed after {retries} attempts: {last_error}")
Enter fullscreen mode Exit fullscreen mode

This handles:

  • Timeouts — Network is slow or API is down
  • Connection errors — No internet, DNS failure
  • 401 Unauthorized — Bad API key (fail immediately, don't retry)
  • 429 Rate Limited — Exponential backoff, then retry
  • Other HTTP errors — Log and fail

Async Python (If You Need Speed)

For high-throughput applications, async code can call multiple APIs simultaneously:

import aiohttp
import asyncio
import os

class AsyncAPIVerveClient:
    BASE_URL = 'https://api.apiverve.com/v1'

    def __init__(self):
        self.api_key = os.environ.get('APIVERVE_KEY')

    async def _request(self, session, endpoint, params=None):
        async with session.get(
            f"{self.BASE_URL}/{endpoint}",
            headers={'x-api-key': self.api_key},
            params=params or {}
        ) as response:
            result = await response.json()
            return result['data']

    async def enrich_lead(self, email, ip):
        """Fetch email validation, IP lookup, and Gravatar in parallel."""
        async with aiohttp.ClientSession() as session:
            results = await asyncio.gather(
                self._request(session, 'emailvalidator', {'email': email}),
                self._request(session, 'iplookup', {'ip': ip}),
                self._request(session, 'gravatarlookup', {'email': email})
            )

            return {
                'email': results[0],
                'location': results[1],
                'profile': results[2]
            }

# Usage
async def main():
    client = AsyncAPIVerveClient()
    lead = await client.enrich_lead('jane@company.com', '173.194.0.1')
    print(f"Lead: {lead['profile'].get('displayName')} from {lead['location']['city']}")

asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

Three API calls, one network round-trip time. If each call takes 200ms, sync code takes 600ms. Async takes ~200ms.

Use this when:

  • You're calling multiple APIs for the same request
  • You're processing batches of items
  • You're building a web service that needs to stay responsive

Don't use this for simple scripts. The complexity isn't worth it for one-off calls.

Data Science / Pandas Integration

If you're working with data frames:

import pandas as pd
import requests
import os
from time import sleep

def validate_emails_batch(df, email_column='email'):
    """Add validation columns to a dataframe."""
    api_key = os.environ.get('APIVERVE_KEY')
    results = []

    for idx, row in df.iterrows():
        email = row[email_column]

        try:
            response = requests.get(
                'https://api.apiverve.com/v1/emailvalidator',
                headers={'x-api-key': api_key},
                params={'email': email},
                timeout=30
            )

            data = response.json()['data']
            results.append({
                'email': email,
                'is_valid': data['isValid'],
                'is_company': data['isCompanyEmail'],
                'domain': data['domain']
            })

        except Exception as e:
            results.append({
                'email': email,
                'is_valid': None,
                'is_company': None,
                'domain': None,
                'error': str(e)
            })

        # Be nice to the API
        sleep(0.1)

    return df.join(pd.DataFrame(results).set_index('email'), on=email_column)

# Usage
leads = pd.read_csv('leads.csv')
enriched = validate_emails_batch(leads)

# Filter to only valid company emails
hot_leads = enriched[
    (enriched['is_valid'] == True) &
    (enriched['is_company'] == True)
]
Enter fullscreen mode Exit fullscreen mode

This adds validation columns to your existing dataframe. You can filter, sort, and analyze using all the pandas tools you already know.

Quick Reference

# Basic GET request
requests.get(url, headers={'x-api-key': key})

# With query parameters
requests.get(url, headers={'x-api-key': key}, params={'email': 'test@example.com'})

# With timeout (always set this!)
requests.get(url, headers={'x-api-key': key}, timeout=30)

# Check response status
response.raise_for_status()  # Throws on 4xx/5xx

# Parse JSON response
data = response.json()['data']

# Environment variables
os.environ.get('APIVERVE_KEY')
Enter fullscreen mode Exit fullscreen mode

What to Build Next

Now that you've got the basics:

  • Email validation in a Flask/FastAPI app — Validate signups before they hit your database
  • Lead enrichment script — Batch process a CSV of leads
  • Location-based features — Use IP lookup to personalize content
  • Automated reports — Pull data from multiple APIs into a scheduled report

The same patterns work for all 300+ APIs. Same authentication, same response format, same error handling.


Python makes API calls simple. The requests library handles all the HTTP complexity. You just need to know the endpoint, the parameters, and how to read the response.

Grab your API key, install requests, and start building. The free tier is enough to build and test just about anything.


Originally published at APIVerve Blog

Top comments (0)