DEV Community

Nishka LLC
Nishka LLC

Posted on Edited on Originally published at sthan.io

How to Add Address Autocomplete to a Python App - Free API Tutorial

Your checkout form collects addresses as freeform text. Users mistype street names, skip apartment numbers, and guess at zip codes. That bad data flows into your database, and each failed delivery means shipping the order again.

Address autocomplete fixes the problem at the source. Users type a few characters, pick the correct address from a dropdown, and you get a postal-formatted string with unit numbers and zip+4 - ready to print on a shipping label.

This tutorial shows you how to add US address autocomplete to a Python app using sthan.io's address API. Works with Flask, Django, FastAPI, or any Python backend.

Quick summary: Install requests, get free credentials from sthan.io, call GET /AutoComplete/USA/Address/{text} with a Bearer token. You get back a JSON array of formatted US addresses - no credit card required.

What you'll need: Python 3.8+ and a free sthan.io account. No credit card, no approval process. The free tier gives you 100,000 requests/month. If each address takes about 5 requests while the user types, that is about 20,000 addresses a month.

Try it first

Type any partial US address - no signup required:

That's what you're building. Type "123 main st" - lowercase, abbreviated, no city or state - and the API returns complete, postal-formatted addresses with apartment numbers, zip+4 codes, and proper casing.

What the API returns

The API wraps every response in an envelope. The address suggestions are in the Result field:

{
  "Id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
  "Result": [
    "123 Main St APT 1, Andover, MA 01810-3816",
    "123 Main St APT 1, Delhi, NY 13753-1257",
    "123 Main St STE 1, Caldwell, ID 83605-5476",
    "123 Main St STE 1, Corinth, NY 12822-1010",
    "123 Main St STE 1, Delhi, NY 13753-1258"
  ],
  "StatusCode": 200,
  "IsError": false,
  "Errors": []
}
Enter fullscreen mode Exit fullscreen mode

Each address in Result includes the full street, unit designation (APT, STE, UNIT), city, state code, and zip+4. The API handles abbreviations (St, Ave, Blvd) and directional prefixes (N, S, E, W).

Step 1: Get your API credentials

  1. Sign up at sthan.io
  2. Go to the API Keys page
  3. Copy your Profile Name and Profile Password

You get credentials as soon as you confirm your email address - no approval queue.

Step 2: Install requests

pip install requests
Enter fullscreen mode Exit fullscreen mode

Step 3: Get an auth token

The API uses JWT authentication. First call gets a token, then you use it for autocomplete requests.

import os
import requests

PROFILE_NAME = os.environ.get("STHAN_PROFILE_NAME", "YOUR_PROFILE_NAME")
PROFILE_PASSWORD = os.environ.get("STHAN_PROFILE_PASSWORD", "YOUR_PROFILE_PASSWORD")
BASE_URL = "https://api.sthan.io"

def get_token():
    response = requests.get(
        f"{BASE_URL}/Auth/Token",
        headers={
            "profileName": PROFILE_NAME,
            "profilePassword": PROFILE_PASSWORD,
        },
    )
    response.raise_for_status()
    data = response.json()
    result = data["Result"]
    return result["access_token"], result["expiration"]

token, expiration = get_token()
print(f"Token expires: {expiration}")
Enter fullscreen mode Exit fullscreen mode

The token lasts 15 minutes on standard accounts. The production client below caches and refreshes it automatically.

Step 4: Call the autocomplete endpoint

from urllib.parse import quote

def autocomplete(query, token):
    response = requests.get(
        f"{BASE_URL}/AutoComplete/USA/Address/{quote(query)}",
        headers={"Authorization": f"Bearer {token}"},
    )
    response.raise_for_status()
    return response.json()["Result"]

results = autocomplete("123 main st", token)
for address in results:
    print(address)
Enter fullscreen mode Exit fullscreen mode

The output matches the JSON shown above - the same five addresses, standardized from the abbreviated input.

Step 5: Production-ready client with token caching

In production, you don't want to fetch a new token on every request. Here's a client class that caches the token and refreshes it on expiry:

import os
import requests
from urllib.parse import quote
from datetime import datetime, timedelta, timezone


class SthanClient:
    def __init__(self, profile_name=None, profile_password=None):
        self.profile_name = profile_name or os.environ["STHAN_PROFILE_NAME"]
        self.profile_password = profile_password or os.environ["STHAN_PROFILE_PASSWORD"]
        self.base_url = "https://api.sthan.io"
        self._token = None
        self._expiration = None

    def _get_token(self):
        if self._token and self._expiration:
            if datetime.now(timezone.utc) < self._expiration:
                return self._token

        response = requests.get(
            f"{self.base_url}/Auth/Token",
            headers={
                "profileName": self.profile_name,
                "profilePassword": self.profile_password,
            },
        )
        response.raise_for_status()
        data = response.json()["Result"]
        self._token = data["access_token"]
        # Tokens last 15 minutes on standard accounts; refresh a minute early
        self._expiration = datetime.now(timezone.utc) + timedelta(minutes=14)
        return self._token

    def autocomplete(self, query, min_length=3):
        """Fetch address suggestions for a partial query."""
        if len(query.strip()) < min_length:
            return []

        token = self._get_token()
        response = requests.get(
            f"{self.base_url}/AutoComplete/USA/Address/{quote(query)}",
            headers={"Authorization": f"Bearer {token}"},
        )
        response.raise_for_status()
        return response.json()["Result"]


# Usage
client = SthanClient()

results = client.autocomplete("123 main st")
for address in results:
    print(address)
Enter fullscreen mode Exit fullscreen mode

This client:

  • Caches the JWT and reuses it across requests
  • Refreshes the token a minute before it expires
  • Enforces a minimum query length (3 characters) to avoid wasting API calls
  • Reads credentials from environment variables by default
  • Works with any Python web framework

Step 6: Add it to a Flask app

Here's a minimal Flask endpoint that your frontend can call:

from flask import Flask, request, jsonify

app = Flask(__name__)
client = SthanClient()  # reads from STHAN_PROFILE_NAME / STHAN_PROFILE_PASSWORD env vars


@app.route("/api/autocomplete")
def autocomplete_endpoint():
    query = request.args.get("q", "")
    if len(query) < 3:
        return jsonify([])
    results = client.autocomplete(query)
    return jsonify(results)


if __name__ == "__main__":
    app.run(port=3000)
Enter fullscreen mode Exit fullscreen mode

Your frontend calls /api/autocomplete?q=123 main st and gets back a JSON array of addresses. Credentials stay on the server - never exposed to the browser.

The same pattern works with Django (views.py), FastAPI (@app.get), or any other Python web framework.

Step 7: Handle errors

Three error codes to handle:

  • 401 - Token expired or invalid. Refresh and retry once.
  • 403 - The account cannot call this API yet: the email address is not confirmed, or the account has no autocomplete plan. Retrying will not help; check your dashboard.
  • 429 - Too many requests. Usually your plan's limit; it is also returned after too many failed token requests from one IP address (wait for the Retry-After header, 60 seconds). Back off and show the user what they've typed so far.
def autocomplete_with_retry(client, query):
    try:
        return client.autocomplete(query)
    except requests.HTTPError as e:
        if e.response.status_code == 401:
            # Force token refresh and retry once
            client._token = None
            return client.autocomplete(query)
        elif e.response.status_code == 429:
            # Too many requests: return empty, don't crash
            return []
        raise
Enter fullscreen mode Exit fullscreen mode

What's next

Address autocomplete is step 1 of a complete address pipeline. If you signed up from the sthan.io home page, your account also has free plans for these APIs (100 requests a month each for the parser, verification and geocoding; 50,000 for IP geolocation):

For a complete Python guide covering all endpoints with async examples, see Integrate Address APIs in Python.

FAQ

How do I add address autocomplete to a Python Flask app?
Install requests, create a SthanClient with your free sthan.io credentials, and expose a /api/autocomplete endpoint. The full working Flask example is in Step 6 above. The same approach works with Django and FastAPI.

How much does the address autocomplete API cost?
The free tier gives you 100,000 requests/month. If each address takes about 5 requests while the user types, that is about 20,000 addresses a month. No credit card required. No trial period. See pricing for higher-volume plans.

What makes this different from geocoding-based autocomplete?
Geocoding APIs are designed to find places - restaurants, landmarks, businesses. They often drop apartment numbers, ignore suite designations, and don't return zip+4 codes. A dedicated address autocomplete API returns postal-formatted mailing addresses from the first keystroke: unit numbers, zip+4, and standard postal abbreviations included.

Does the API support CORS for browser requests?
No. Call it from your Python backend, not the browser. The Flask proxy in Step 6 handles this - your frontend calls your server, your server calls the API.

What is the response time for autocomplete requests?
In our test on October 5, 2026, repeat prefixes came back in under 100 ms and new ones in about 400 to 500 ms. That is fast enough for suggestions as users type.

Can I use this with Django or FastAPI instead of Flask?
Yes. The SthanClient class is framework-agnostic. Wire it to any route that accepts a query parameter. For Django: use it in views.py. For FastAPI: use it with @app.get.

Get started

The code above works. Copy it. The free tier is 100,000 requests a month with no credit card.

Create your free sthan.io account and add autocomplete to your Python app.


sthan.io - Address APIs Built for Scale, Priced for Everyone

Top comments (0)