Skip to content

Jurisdiction API - Implementation Guide

Practical examples and patterns for integrating with the Jurisdiction API


Table of Contents


Get all jurisdiction data with one API call using the consolidated endpoint.

The /api/jurisdictions/lookup endpoint returns all regions, jurisdictions, and counts in a single response - perfect for dashboards and overview pages.

JavaScript/React

React Hook Example

import { useQuery } from '@tanstack/react-query';

function JurisdictionDashboard() {
  const API_KEY = process.env.REACT_APP_JURISDICTION_API_KEY;

  const { data, isLoading, error } = useQuery({
    queryKey: ['jurisdiction-lookup'],
    queryFn: async () => {
      const response = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
        headers: {
          'Authorization': `Bearer ${API_KEY}`
        }
      });

      if (!response.ok) {
        throw new Error('Failed to fetch jurisdiction data');
      }

      return response.json();
    }
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>Jurisdiction Overview</h1>

      {/* Display totals */}
      <div className="stats">
        <div>Total Jurisdictions: {data.totals.jurisdictions}</div>
        <div>Total Agencies: {data.totals.agencies}</div>
        <div>Total Contributors: {data.totals.contributors}</div>
        <div>Total Sources: {data.totals.sources}</div>
      </div>

      {/* Display regions and jurisdictions */}
      {data.regions.map(region => (
        <div key={region.id}>
          <h2>{region.name}</h2>

          {region.jurisdictions.map(jurisdiction => (
            <div key={jurisdiction.id}>
              <h3>{jurisdiction.name}</h3>
              <p>Agencies: {jurisdiction.agencyCount}</p>
              <p>Contributors: {jurisdiction.contributorCount}</p>
              <p>Sources: {jurisdiction.sourceCount}</p>
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

Plain JavaScript Example

async function fetchJurisdictionData() {
  const API_KEY = 'your_api_key_here';

  try {
    const response = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      }
    });

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

    const data = await response.json();

    // Access the data
    console.log('Total jurisdictions:', data.totals.jurisdictions);

    // Loop through regions
    data.regions.forEach(region => {
      console.log(`Region: ${region.name}`);

      region.jurisdictions.forEach(jurisdiction => {
        console.log(`  - ${jurisdiction.name}`);
        console.log(`    Agencies: ${jurisdiction.agencyCount}`);
        console.log(`    Contributors: ${jurisdiction.contributorCount}`);
        console.log(`    Sources: ${jurisdiction.sourceCount}`);
      });
    });

    return data;
  } catch (error) {
    console.error('Error fetching jurisdiction data:', error);
    throw error;
  }
}

// Use it
fetchJurisdictionData()
  .then(data => {
    // Do something with the data
  });

Node.js

Node.js with Fetch

// Using built-in fetch (Node 18+)
const API_KEY = process.env.JURISDICTION_API_KEY;

async function getJurisdictionLookup() {
  const response = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
    headers: {
      'Authorization': `Bearer ${API_KEY}`
    }
  });

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

  const data = await response.json();
  return data;
}

// Example: Find jurisdiction by name
async function findJurisdiction(jurisdictionName) {
  const data = await getJurisdictionLookup();

  for (const region of data.regions) {
    const jurisdiction = region.jurisdictions.find(
      j => j.name.toLowerCase() === jurisdictionName.toLowerCase()
    );

    if (jurisdiction) {
      return {
        jurisdiction,
        region: region.name
      };
    }
  }

  return null;
}

// Example: Get all jurisdictions with more than X agencies
async function getJurisdictionsWithMinAgencies(minAgencies) {
  const data = await getJurisdictionLookup();
  const results = [];

  data.regions.forEach(region => {
    region.jurisdictions.forEach(jurisdiction => {
      if (jurisdiction.agencyCount >= minAgencies) {
        results.push({
          name: jurisdiction.name,
          region: region.name,
          agencyCount: jurisdiction.agencyCount
        });
      }
    });
  });

  return results;
}

// Usage
findJurisdiction('Los Angeles')
  .then(result => {
    if (result) {
      console.log(`Found in region: ${result.region}`);
      console.log(`Agencies: ${result.jurisdiction.agencyCount}`);
    }
  });

Node.js with Axios

const axios = require('axios');

const api = axios.create({
  baseURL: 'https://your-app.replit.app',
  headers: {
    'Authorization': `Bearer ${process.env.JURISDICTION_API_KEY}`
  }
});

async function getJurisdictionLookup() {
  try {
    const response = await api.get('/api/jurisdictions/lookup');
    return response.data;
  } catch (error) {
    if (error.response) {
      console.error('API Error:', error.response.status, error.response.data);
    } else if (error.request) {
      console.error('Network Error:', error.message);
    } else {
      console.error('Error:', error.message);
    }
    throw error;
  }
}

// Export for use in other modules
module.exports = { getJurisdictionLookup };

Python

Python with Requests

import requests
import os
from typing import Dict, List, Optional

class JurisdictionAPI:
    def __init__(self):
        self.base_url = 'https://your-app.replit.app'
        self.api_key = os.environ.get('JURISDICTION_API_KEY')
        self.headers = {
            'Authorization': f'Bearer {self.api_key}'
        }

    def get_jurisdiction_lookup(self) -> Dict:
        """Get all jurisdiction data with counts"""
        response = requests.get(
            f'{self.base_url}/api/jurisdictions/lookup',
            headers=self.headers
        )
        response.raise_for_status()
        return response.json()

    def find_jurisdiction(self, jurisdiction_name: str) -> Optional[Dict]:
        """Find a jurisdiction by name"""
        data = self.get_jurisdiction_lookup()

        for region in data['regions']:
            for jurisdiction in region['jurisdictions']:
                if jurisdiction['name'].lower() == jurisdiction_name.lower():
                    return {
                        'jurisdiction': jurisdiction,
                        'region': region['name']
                    }

        return None

    def get_region_summary(self, region_name: str) -> Dict:
        """Get summary statistics for a region"""
        data = self.get_jurisdiction_lookup()

        for region in data['regions']:
            if region['name'].lower() == region_name.lower():
                total_agencies = sum(j['agencyCount'] for j in region['jurisdictions'])
                total_contributors = sum(j['contributorCount'] for j in region['jurisdictions'])
                total_sources = sum(j['sourceCount'] for j in region['jurisdictions'])

                return {
                    'region': region['name'],
                    'jurisdictions': len(region['jurisdictions']),
                    'agencies': total_agencies,
                    'contributors': total_contributors,
                    'sources': total_sources
                }

        return None

# Usage Example
if __name__ == '__main__':
    api = JurisdictionAPI()

    # Get all data
    data = api.get_jurisdiction_lookup()
    print(f"Total jurisdictions: {data['totals']['jurisdictions']}")

    # Find specific jurisdiction
    result = api.find_jurisdiction('San Francisco')
    if result:
        print(f"Found in region: {result['region']}")
        print(f"Agencies: {result['jurisdiction']['agencyCount']}")

    # Get region summary
    summary = api.get_region_summary('California')
    if summary:
        print(f"Region {summary['region']} has:")
        print(f"  - {summary['jurisdictions']} jurisdictions")
        print(f"  - {summary['agencies']} agencies")

Drill-Down Pattern: Getting Detailed Information

When you need complete details about agencies, contributors, or sources beyond just counts.

Get Agencies

Fetch all agencies for a jurisdiction with complete details.

// JavaScript Example
async function getAgenciesForJurisdiction(jurisdictionId) {
  const API_KEY = process.env.JURISDICTION_API_KEY;

  const response = await fetch(
    `https://your-app.replit.app/api/jurisdictions/${jurisdictionId}/agencies`,
    {
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      }
    }
  );

  if (!response.ok) {
    throw new Error('Failed to fetch agencies');
  }

  const agencies = await response.json();
  return agencies;
}

// Usage: First get the jurisdiction ID from lookup, then fetch agencies
async function getAgenciesByJurisdictionName(jurisdictionName) {
  // Step 1: Get lookup data to find the jurisdiction ID
  const lookupResponse = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
    headers: { 'Authorization': `Bearer ${API_KEY}` }
  });
  const lookupData = await lookupResponse.json();

  // Step 2: Find the jurisdiction
  let jurisdictionId = null;
  for (const region of lookupData.regions) {
    const jurisdiction = region.jurisdictions.find(
      j => j.name === jurisdictionName
    );
    if (jurisdiction) {
      jurisdictionId = jurisdiction.id;
      break;
    }
  }

  if (!jurisdictionId) {
    throw new Error(`Jurisdiction "${jurisdictionName}" not found`);
  }

  // Step 3: Fetch the agencies
  const agencies = await getAgenciesForJurisdiction(jurisdictionId);

  return agencies;
}

// Example
getAgenciesByJurisdictionName('Los Angeles')
  .then(agencies => {
    agencies.forEach(agency => {
      console.log(`Agency: ${agency.name}`);
      console.log(`  Original ID: ${agency.original_id}`);
    });
  });

Get Contributors

Fetch all contributors for a jurisdiction.

# Python Example
import requests

def get_contributors_for_jurisdiction(jurisdiction_id: str, api_key: str):
    """Get all contributors for a specific jurisdiction"""
    response = requests.get(
        f'https://your-app.replit.app/api/jurisdictions/{jurisdiction_id}/contributors',
        headers={'Authorization': f'Bearer {api_key}'}
    )
    response.raise_for_status()
    return response.json()

# Complete example: Get contributors by jurisdiction name
def get_contributors_by_name(jurisdiction_name: str, api_key: str):
    # First get the lookup data
    lookup_response = requests.get(
        'https://your-app.replit.app/api/jurisdictions/lookup',
        headers={'Authorization': f'Bearer {api_key}'}
    )
    lookup_data = lookup_response.json()

    # Find the jurisdiction ID
    jurisdiction_id = None
    for region in lookup_data['regions']:
        for jurisdiction in region['jurisdictions']:
            if jurisdiction['name'] == jurisdiction_name:
                jurisdiction_id = jurisdiction['id']
                break
        if jurisdiction_id:
            break

    if not jurisdiction_id:
        raise ValueError(f'Jurisdiction "{jurisdiction_name}" not found')

    # Get the contributors
    contributors = get_contributors_for_jurisdiction(jurisdiction_id, api_key)

    return contributors

# Usage
api_key = os.environ['JURISDICTION_API_KEY']
contributors = get_contributors_by_name('San Francisco', api_key)

for contributor in contributors:
    print(f"Contributor: {contributor['name']}")
    print(f"  ID: {contributor['id']}")

Get Sources

Fetch all sources for a contributor.

// Node.js Example
async function getSourcesForContributor(contributorId) {
  const API_KEY = process.env.JURISDICTION_API_KEY;

  const response = await fetch(
    `https://your-app.replit.app/api/contributors/${contributorId}/sources`,
    {
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      }
    }
  );

  if (!response.ok) {
    throw new Error(`Failed to fetch sources: ${response.statusText}`);
  }

  return await response.json();
}

// Complete workflow: Get all sources for a specific contributor
async function getAllSourcesForContributor(contributorName, jurisdictionName) {
  const API_KEY = process.env.JURISDICTION_API_KEY;

  // Step 1: Get lookup data
  const lookupResponse = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
    headers: { 'Authorization': `Bearer ${API_KEY}` }
  });
  const lookupData = await lookupResponse.json();

  // Step 2: Find jurisdiction ID
  let jurisdictionId = null;
  for (const region of lookupData.regions) {
    const jurisdiction = region.jurisdictions.find(j => j.name === jurisdictionName);
    if (jurisdiction) {
      jurisdictionId = jurisdiction.id;
      break;
    }
  }

  if (!jurisdictionId) {
    throw new Error(`Jurisdiction "${jurisdictionName}" not found`);
  }

  // Step 3: Get contributors for that jurisdiction
  const contributorsResponse = await fetch(
    `https://your-app.replit.app/api/jurisdictions/${jurisdictionId}/contributors`,
    { headers: { 'Authorization': `Bearer ${API_KEY}` } }
  );
  const contributors = await contributorsResponse.json();

  // Step 4: Find the specific contributor
  const contributor = contributors.find(c => c.name === contributorName);
  if (!contributor) {
    throw new Error(`Contributor "${contributorName}" not found`);
  }

  // Step 5: Get sources for that contributor
  const sources = await getSourcesForContributor(contributor.id);

  return sources;
}

// Usage
getAllSourcesForContributor('John Doe', 'Los Angeles')
  .then(sources => {
    console.log(`Found ${sources.length} sources`);
    sources.forEach(source => {
      console.log(`  - ${source.name}`);
    });
  })
  .catch(error => console.error(error));

Common Usage Patterns

Pattern 1: Caching Lookup Data

Cache the lookup data to minimize API calls and improve performance.

class JurisdictionCache {
  constructor(apiKey, cacheTimeMs = 5 * 60 * 1000) { // 5 minute default
    this.apiKey = apiKey;
    this.cacheTimeMs = cacheTimeMs;
    this.cache = null;
    this.cacheTimestamp = null;
  }

  async getLookupData() {
    const now = Date.now();

    // Return cached data if still valid
    if (this.cache && this.cacheTimestamp) {
      if (now - this.cacheTimestamp < this.cacheTimeMs) {
        return this.cache;
      }
    }

    // Fetch fresh data
    const response = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
      headers: { 'Authorization': `Bearer ${this.apiKey}` }
    });

    if (!response.ok) {
      throw new Error('Failed to fetch jurisdiction data');
    }

    this.cache = await response.json();
    this.cacheTimestamp = now;

    return this.cache;
  }

  invalidateCache() {
    this.cache = null;
    this.cacheTimestamp = null;
  }
}

// Usage
const cache = new JurisdictionCache(process.env.JURISDICTION_API_KEY);

// First call fetches from API
const data1 = await cache.getLookupData();

// Subsequent calls use cache (within 5 minutes)
const data2 = await cache.getLookupData(); // Returns cached data

// Force refresh
cache.invalidateCache();
const data3 = await cache.getLookupData(); // Fetches fresh data

Pattern 2: Search and Filter

Implement search functionality across jurisdictions.

async function searchJurisdictions(searchTerm) {
  const response = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
    headers: { 'Authorization': `Bearer ${process.env.JURISDICTION_API_KEY}` }
  });
  const data = await response.json();

  const results = [];
  const search = searchTerm.toLowerCase();

  data.regions.forEach(region => {
    region.jurisdictions.forEach(jurisdiction => {
      // Search by jurisdiction name or region name
      if (jurisdiction.name.toLowerCase().includes(search) ||
          region.name.toLowerCase().includes(search)) {
        results.push({
          ...jurisdiction,
          regionName: region.name,
          regionId: region.id
        });
      }
    });
  });

  return results;
}

// Usage
const results = await searchJurisdictions('san');
// Returns: San Francisco, San Diego, San Jose, etc.

Pattern 3: Generate Statistics

Calculate custom statistics from the lookup data.

async function generateStatistics() {
  const response = await fetch('https://your-app.replit.app/api/jurisdictions/lookup', {
    headers: { 'Authorization': `Bearer ${process.env.JURISDICTION_API_KEY}` }
  });
  const data = await response.json();

  const stats = {
    // Overall totals (already provided)
    totals: data.totals,

    // Per-region breakdown
    regionBreakdown: data.regions.map(region => ({
      name: region.name,
      jurisdictionCount: region.jurisdictions.length,
      totalAgencies: region.jurisdictions.reduce((sum, j) => sum + j.agencyCount, 0),
      totalContributors: region.jurisdictions.reduce((sum, j) => sum + j.contributorCount, 0),
      totalSources: region.jurisdictions.reduce((sum, j) => sum + j.sourceCount, 0)
    })),

    // Top jurisdictions by agency count
    topJurisdictionsByAgencies: data.regions
      .flatMap(region => 
        region.jurisdictions.map(j => ({
          ...j,
          regionName: region.name
        }))
      )
      .sort((a, b) => b.agencyCount - a.agencyCount)
      .slice(0, 10),

    // Average agencies per jurisdiction
    avgAgenciesPerJurisdiction: data.totals.agencies / data.totals.jurisdictions
  };

  return stats;
}

// Usage
const stats = await generateStatistics();
console.log(`Average agencies per jurisdiction: ${stats.avgAgenciesPerJurisdiction.toFixed(2)}`);
console.log('Top 10 jurisdictions:', stats.topJurisdictionsByAgencies);

Pattern 4: Robust Error Handling

Handle common error scenarios gracefully.

async function fetchWithErrorHandling(url, apiKey, retries = 3) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      const response = await fetch(url, {
        headers: {
          'Authorization': `Bearer ${apiKey}`
        }
      });

      // Handle different HTTP status codes
      if (response.status === 401) {
        throw new Error('Invalid API key. Please check your credentials.');
      }

      if (response.status === 404) {
        throw new Error('Resource not found. Check the endpoint URL.');
      }

      if (response.status === 429) {
        // Rate limited - wait and retry
        if (attempt < retries) {
          const waitTime = Math.pow(2, attempt) * 1000; // Exponential backoff
          console.log(`Rate limited. Retrying in ${waitTime}ms...`);
          await new Promise(resolve => setTimeout(resolve, waitTime));
          continue;
        }
        throw new Error('Rate limit exceeded. Please try again later.');
      }

      if (response.status >= 500) {
        // Server error - retry
        if (attempt < retries) {
          console.log(`Server error. Retry attempt ${attempt}/${retries}`);
          await new Promise(resolve => setTimeout(resolve, 1000));
          continue;
        }
        throw new Error('Server error. Please try again later.');
      }

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

      return await response.json();

    } catch (error) {
      if (attempt === retries) {
        throw error;
      }

      // Network error - retry
      console.log(`Network error. Retry attempt ${attempt}/${retries}`);
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
}

// Usage
try {
  const data = await fetchWithErrorHandling(
    'https://your-app.replit.app/api/jurisdictions/lookup',
    process.env.JURISDICTION_API_KEY
  );
  console.log('Data fetched successfully');
} catch (error) {
  console.error('Failed to fetch data:', error.message);
  // Handle error appropriately (show user message, log to monitoring, etc.)
}

Best Practices

Use Environment Variables for API Keys

Never hardcode API keys in your source code. Use environment variables (process.env.JURISDICTION_API_KEY) and keep them out of version control.

// ✅ GOOD
const API_KEY = process.env.JURISDICTION_API_KEY;

// ❌ BAD
const API_KEY = 'sk_live_abc123def456'; // Never do this!

Cache Lookup Data

The jurisdiction lookup data doesn't change frequently. Cache it on the client side for 5-10 minutes to reduce API calls and improve performance.

// Use a caching layer like the JurisdictionCache class shown above
const cache = new JurisdictionCache(apiKey, 5 * 60 * 1000); // 5 minutes

Use the Consolidated Endpoint First

Start with /api/jurisdictions/lookup to get overview data. Only use the detailed endpoints when you need complete lists of agencies, contributors, or sources.

// ✅ GOOD - Single call for overview
const data = await fetch('/api/jurisdictions/lookup');

// ❌ LESS EFFICIENT - Multiple calls for the same data
const regions = await fetch('/api/regions');
for (const region of regions) {
  const jurisdictions = await fetch(`/api/regions/${region.id}/jurisdictions`);
  // ... more calls
}

Implement Error Handling

Always handle potential errors: invalid API keys (401), rate limits (429), server errors (500+), and network failures. Use retries with exponential backoff for transient errors.

// Use the fetchWithErrorHandling function shown above
const data = await fetchWithErrorHandling(url, apiKey, 3);

Respect Rate Limits

Implement caching and avoid making unnecessary API calls in loops. If you need to fetch data for multiple jurisdictions, use the consolidated endpoint to get everything at once.

// ✅ GOOD - One call gets all data
const allData = await fetch('/api/jurisdictions/lookup');

// ❌ BAD - Loop making many API calls
for (const jurisdictionId of jurisdictionIds) {
  await fetch(`/api/jurisdictions/${jurisdictionId}/agencies`); // Too many calls!
}

Response Format Examples

Consolidated Lookup Response

{
  "regions": [
    {
      "id": "uuid",
      "original_id": 1,
      "name": "Region Name",
      "jurisdictions": [
        {
          "id": "uuid",
          "original_id": 1,
          "name": "Jurisdiction Name",
          "agencychannel": 123,
          "jurisdictionchannel": 456,
          "agencyCount": 5,
          "contributorCount": 3,
          "sourceCount": 8
        }
      ]
    }
  ],
  "totals": {
    "jurisdictions": 10,
    "agencies": 50,
    "contributors": 30,
    "sources": 85
  }
}

Agency Details Response

[
  {
    "id": "uuid",
    "original_id": 1,
    "name": "Agency Name",
    "jurisdiction_name": "Jurisdiction Name",
    "region_name": "Region Name"
  }
]

Support

For API documentation and reference, visit:

  • API Documentation: https://your-app.replit.app/api-docs
  • Implementation Guide: https://your-app.replit.app/implementation-guide

For API key management, log in to your admin dashboard.


Last Updated: November 2025


Last update: December 22, 2025
Back to top