Redirections
Code Examples

Python Examples

Integration examples using the requests library.

This page provides ready-to-integrate Python code for the Redirections API using the popular requests library.

Prerequisites

Install the requests library:

pip install requests

Configuration

Start by defining your API credentials and base URL:

import requests
import time

API_KEY = 'redir_live_your_key_here'
PROJECT_ID = '<project_id>'
BASE_URL = 'https://api.3xx.app'

Replace API_KEY and PROJECT_ID with your actual credentials.


Lookup a Redirect

This function looks up a redirect for a given path and returns the destination URL, status code, and match type.

def lookup_redirect(path, version=None):
    """
    Look up a redirect for the given path.

    Args:
        path: The URL path to look up (e.g., '/old-blog')
        version: Optional version number to query

    Returns:
        dict with destination, statusCode, matchType, or None if no match

    Raises:
        requests.HTTPError: If the API returns an error
    """
    # Build query parameters
    params = {
        'project': PROJECT_ID,
        'path': path,
    }

    if version:
        params['version'] = str(version)

    # Build headers
    headers = {
        'X-API-Key': API_KEY,
    }

    # Make API request
    response = requests.get(
        f'{BASE_URL}/v1/lookup',
        params=params,
        headers=headers
    )

    # Handle 204 No Content (no redirect found)
    if response.status_code == 204:
        return None

    # Raise exception for error status codes
    response.raise_for_status()

    # Return successful result
    return response.json()


# Usage example
if __name__ == '__main__':
    try:
        result = lookup_redirect('/old-blog')

        if result:
            print('Redirect found:')
            print(f"  Destination: {result['destination']}")
            print(f"  Status Code: {result['statusCode']}")
            print(f"  Match Type: {result['matchType']}")
        else:
            print('No redirect found for this path')

    except requests.HTTPError as e:
        print(f'Lookup failed: {e}')

Expected Output:

Redirect found:
  Destination: /blog
  Status Code: 301
  Match Type: exact

Export Redirects

This function downloads an export in the specified format and saves it to a file.

def export_redirects(format, output_path, version=None):
    """
    Export redirects in the specified format.

    Args:
        format: Export format (csv, nginx, haproxy, etc.)
        output_path: Path to save the export file
        version: Optional version number to export

    Raises:
        requests.HTTPError: If the API returns an error
    """
    # Build query parameters
    params = {
        'project': PROJECT_ID,
        'format': format,
    }

    if version:
        params['version'] = str(version)

    # Build headers
    headers = {
        'X-API-Key': API_KEY,
    }

    # Make API request
    response = requests.get(
        f'{BASE_URL}/v1/export',
        params=params,
        headers=headers
    )

    # Raise exception for error status codes
    response.raise_for_status()

    # Save to file
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(response.text)

    print(f'Export saved to {output_path}')


# Usage example
if __name__ == '__main__':
    try:
        export_redirects('csv', 'redirects.csv')
        export_redirects('haproxy', 'redirects.cfg')
        export_redirects('nginx', 'redirects.conf')
    except requests.HTTPError as e:
        print(f'Export failed: {e}')

Available formats: csv, nginx, nginx-map-exact, nginx-map-prefix, haproxy, haproxy-map-exact, haproxy-map-prefix


Error Handling

Handle API errors with proper error parsing and specific responses for different error codes.

def lookup_redirect_with_error_handling(path):
    """
    Look up a redirect with comprehensive error handling.

    Args:
        path: The URL path to look up

    Returns:
        dict with redirect info, or None if no match

    Raises:
        Exception: For various error conditions
    """
    try:
        params = {
            'project': PROJECT_ID,
            'path': path,
        }

        headers = {
            'X-API-Key': API_KEY,
        }

        response = requests.get(
            f'{BASE_URL}/v1/lookup',
            params=params,
            headers=headers
        )

        # Success: 204 No Content
        if response.status_code == 204:
            return None

        # Success: 200 OK
        if response.ok:
            return response.json()

        # Error: Parse error response
        try:
            error_data = response.json()
            error_code = error_data.get('code', 'UNKNOWN')
            error_message = error_data.get('error', 'Unknown error')
        except ValueError:
            # Response is not JSON
            error_code = 'UNKNOWN'
            error_message = response.text or 'Unknown error'

        # Handle specific error codes
        if error_code == 'INVALID_API_KEY':
            raise Exception('Invalid API key. Please check your credentials.')

        elif error_code == 'MISSING_PATH':
            raise Exception('Path parameter is required.')

        elif error_code == 'RATE_LIMIT_EXCEEDED':
            # Read Retry-After header
            retry_after = response.headers.get('Retry-After')
            if retry_after:
                wait_seconds = int(retry_after)
                print(f'Rate limited. Waiting {wait_seconds} seconds...')

                # Wait and retry
                time.sleep(wait_seconds)
                return lookup_redirect_with_error_handling(path)

            raise Exception('Rate limit exceeded. Please try again later.')

        elif error_code == 'QUOTA_EXCEEDED':
            raise Exception('Monthly quota exceeded. Upgrade your plan or wait until next month.')

        else:
            raise Exception(f'API error: {error_message} ({error_code})')

    except requests.RequestException as e:
        # Network error
        raise Exception(f'Network error: Unable to reach API. {e}')


# Usage
if __name__ == '__main__':
    try:
        result = lookup_redirect_with_error_handling('/old-blog')
        print(f'Success: {result}')
    except Exception as e:
        print(f'Error: {e}')

Batch Lookups

Process multiple paths efficiently with a simple loop:

def batch_lookup_redirects(paths):
    """
    Look up redirects for multiple paths.

    Args:
        paths: List of URL paths to look up

    Returns:
        dict mapping paths to their redirect info (or None if no match)
    """
    results = {}

    for path in paths:
        try:
            result = lookup_redirect(path)
            results[path] = result

            # Be respectful of rate limits
            time.sleep(0.1)  # 100ms delay between requests

        except requests.HTTPError as e:
            print(f'Error looking up {path}: {e}')
            results[path] = None

    return results


# Usage example
if __name__ == '__main__':
    paths_to_check = [
        '/old-blog',
        '/old-about',
        '/old-contact',
        '/missing-page',
    ]

    results = batch_lookup_redirects(paths_to_check)

    for path, redirect in results.items():
        if redirect:
            print(f'{path} -> {redirect["destination"]} ({redirect["statusCode"]})')
        else:
            print(f'{path} -> No redirect')

Expected Output:

/old-blog -> /blog (301)
/old-about -> /about (301)
/old-contact -> /contact (301)
/missing-page -> No redirect

Next Steps

For a complete reference of all error codes and their meanings, see the Error Reference page.