Skip to main content

A modern Python client for the Apple Maps Server API with automatic JWT management and type safety

Project description

Release Notes Downloads GitHub CI Status License: MIT

Python Client for Apple Maps Server API

A modern, type-safe Python client for the Apple Maps Server API.

There's no python library for the Apple Maps API. Maps is super cheap compared to all of the alternatives, so with AI I figured it wouldn't be too hard to build a client library.

The goal of this library is to provide similar functionality to the radar python client. Here's the main goals:

  • Automatic JWT Management: Handles signing and periodic refresh of Apple's ES256 tokens.
  • Type-Safe: Built with Pydantic models for all API responses, giving you excellent IDE support.
  • Resilient: Automatic retries with exponential backoff for transient network and server errors.
  • Modern: Uses httpx for synchronous requests, with a structure that's ready for future async support.

Installation

uv add apple-maps-api

Usage

Basic Setup

You'll need your Team ID, Key ID, and the private key from your Apple Developer account.

from apple_maps_api import AppleMapsClient

client = AppleMapsClient(
    team_id="YOUR_TEAM_ID",
    key_id="YOUR_KEY_ID",
    private_key="""-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----"""
)

Or load credentials from environment variables:

export APPLE_MAPS_TEAM_ID=...
export APPLE_MAPS_KEY_ID=...
export APPLE_MAPS_P8_KEY=...   # PEM or raw base64 DER
# optional: export APPLE_MAPS_ORIGIN=https://example.com

And then you can source the vars from the env:

from apple_maps_api import AppleMapsClient

client = AppleMapsClient.from_env()

Geocoding

Convert an address string to coordinates:

results = client.geocode("1 Apple Park Way, Cupertino, CA")

for place in results.results:
    print(f"{place.name}: {place.coordinate.latitude}, {place.coordinate.longitude}")

# place.name                              => "1 Apple Park Way"
# place.coordinate.latitude               => 37.334859
# place.coordinate.longitude              => -122.0090403
# place.formattedAddressLines             => ["1 Apple Park Way", "Cupertino, CA  95014", "United States"]
# place.structuredAddress.locality        => "Cupertino"

Reverse Geocoding

Convert coordinates back to a structured address:

results = client.reverse_geocode((37.3346, -122.0090))

if results.results:
    print(results.results[0].formattedAddressLines)

# place.formattedAddressLines      => ["Apple Park", "1 Apple Park Way", "Cupertino, CA  95014", "United States"]
# place.structuredAddress.locality => "Cupertino"
# place.structuredAddress.postCode => "95014"

Place Search

Search for points of interest near a location:

results = client.search("pizza", near="37.3346,-122.0090")
# or: client.search("pizza", lat=37.3346, lng=-122.0090)

for place in results.results:
    print(f"{place.name} - {place.formattedAddressLines}")

# results.results[0].name                  => "Pizza My Heart"
# results.results[0].formattedAddressLines => ["19409 Stevens Creek Blvd", "Cupertino, CA  95014", "United States"]
# results.results[1].name                  => "Mountain Mike's Pizza"
# results.results[2].name                  => "Pizz'a Chicago"

Address Autocomplete

Provide search completions for a partial query and filter by country:

results = client.autocomplete("1 Apple Park", limit_to_countries="US", lat=37.3346, lng=-122.0090)

for completion in results.results:
    print(completion.displayLines)

# results.results[0].displayLines => ["1 Apple Park Way", "Cupertino, CA, United States"]
# results.results[1].displayLines => ["1 Apple Hill Dr", "Natick, MA, United States"]
# results.results[0].completionUrl => "/v1/search?q=1%20Apple%20Park%20Way..."

Helper Functions

The library includes high-level helpers for common geocoding operations:

from apple_maps_api import geocode_postal_code, geocode_coordinates

# Geocode a postal code
result = geocode_postal_code(client, postal_code="95014", country="US")
# result.lat              => 37.2895111
# result.lon              => -122.0811912
# result.city             => "Cupertino"
# result.state_code       => "CA"
# result.postal_code      => "95014"
# result.formatted_address => "Cupertino, CA  95014, United States"

# Reverse geocode coordinates
result = geocode_coordinates(client, lat=37.3346, lon=-122.0090)
# result.address1          => "1 Apple Park Way"
# result.postal_code       => "95014"
# result.city              => "Cupertino"
# result.state_code        => "CA"
# result.formatted_address => "Apple Park, 1 Apple Park Way, Cupertino, CA  95014, United States"

Example Payloads

These examples show the real data shapes returned by the Apple Maps API for common operations.

Note on city names: Apple Maps uses its own administrative boundaries. The city field on GeocodeResult maps to structuredAddress.locality, which may differ from the colloquial city name. For example, postal code 90210 returns city="Los Angeles" even though the formatted address reads "Beverly Hills" — Beverly Hills is an independent city but Apple Maps assigns it to the LA locality.

Geocoding a postal code

result = geocode_postal_code(client, postal_code="10001")
# result.lat             => 40.7504876
# result.lon             => -74.0025705
# result.city            => "New York"
# result.state_code      => "NY"
# result.postal_code     => "10001"
# result.formatted_address => "New York, NY  10001, United States"
result = geocode_postal_code(client, postal_code="90210")
# result.lat             => 34.1025226
# result.lon             => -118.4167959
# result.city            => "Los Angeles"   # NOT "Beverly Hills"
# result.state_code      => "CA"
# result.postal_code     => "90210"
# result.formatted_address => "Beverly Hills, CA  90210, United States"

Reverse geocoding coordinates

# Times Square, NYC
result = geocode_coordinates(client, lat=40.7589, lon=-73.9851)
# result.address1          => "1552–1568 Broadway"
# result.postal_code       => "10036"
# result.city              => "New York"
# result.state_code        => "NY"
# result.formatted_address => "Times Square, 1552–1568 Broadway, New York, NY  10036, United States"

Raw reverse_geocode response — full structuredAddress

Apple Park, Cupertino CA (37.3346, -122.0090):

place = client.reverse_geocode((37.3346, -122.0090)).results[0]
# place.name                                      => "Apple Park"
# place.formattedAddressLines                     => ["Apple Park", "1 Apple Park Way", "Cupertino, CA  95014", "United States"]
# place.structuredAddress.administrativeArea      => "California"
# place.structuredAddress.administrativeAreaCode  => "CA"
# place.structuredAddress.subAdministrativeArea   => None
# place.structuredAddress.locality                => "Cupertino"
# place.structuredAddress.subLocality             => None
# place.structuredAddress.fullThoroughfare        => "1 Apple Park Way"
# place.structuredAddress.thoroughfare            => "Apple Park Way"
# place.structuredAddress.subThoroughfare         => "1"
# place.structuredAddress.postCode                => "95014"
# place.structuredAddress.areasOfInterest         => ["Apple Park"]
# place.structuredAddress.dependentLocalities     => None

Times Square, NYC (40.7589, -73.9851):

place = client.reverse_geocode((40.7589, -73.9851)).results[0]
# place.name                                      => "Times Square"
# place.formattedAddressLines                     => ["Times Square", "1552–1568 Broadway", "New York, NY  10036", "United States"]
# place.structuredAddress.administrativeArea      => "New York"
# place.structuredAddress.administrativeAreaCode  => "NY"
# place.structuredAddress.subAdministrativeArea   => None
# place.structuredAddress.locality                => "New York"
# place.structuredAddress.subLocality             => "Manhattan"
# place.structuredAddress.fullThoroughfare        => "1552–1568 Broadway"
# place.structuredAddress.thoroughfare            => "Broadway"
# place.structuredAddress.subThoroughfare         => "1552–1568"
# place.structuredAddress.postCode                => "10036"
# place.structuredAddress.areasOfInterest         => ["Times Square", "Manhattan"]
# place.structuredAddress.dependentLocalities     => ["Broadway", "Times Square", "Theater District", "Midtown Manhattan", "Midtown", "North Hudson"]

Beverly Hills, CA (34.1025226, -118.4167959) — note locality vs formatted address mismatch:

place = client.reverse_geocode((34.1025226, -118.4167959)).results[0]
# place.name                                      => "1731 N Franklin Canyon Dr"
# place.formattedAddressLines                     => ["1731 N Franklin Canyon Dr", "Beverly Hills, CA  90210", "United States"]
# place.structuredAddress.administrativeArea      => "California"
# place.structuredAddress.administrativeAreaCode  => "CA"
# place.structuredAddress.subAdministrativeArea   => None
# place.structuredAddress.locality                => "Los Angeles"   # NOT "Beverly Hills"
# place.structuredAddress.subLocality             => "Beverly Crest"
# place.structuredAddress.fullThoroughfare        => "1731 N Franklin Canyon Dr"
# place.structuredAddress.thoroughfare            => "N Franklin Canyon Dr"
# place.structuredAddress.subThoroughfare         => "1731"
# place.structuredAddress.postCode                => "90210"
# place.structuredAddress.areasOfInterest         => None
# place.structuredAddress.dependentLocalities     => ["Beverly Crest"]

MIT License


This project was created from iloveitaly/python-package-template

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

apple_maps_api-0.1.0.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

apple_maps_api-0.1.0-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file apple_maps_api-0.1.0.tar.gz.

File metadata

  • Download URL: apple_maps_api-0.1.0.tar.gz
  • Upload date:
  • Size: 13.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for apple_maps_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7646ddbafc2d67a467b44998b31d757bf5a9b260bef1dfc466397666eb393064
MD5 4e5b3038b88dce43dda66fd191e0e198
BLAKE2b-256 a5f185ecb828be20b778370f8adb81bfc120e22528ef15cb208efda858b7aa15

See more details on using hashes here.

File details

Details for the file apple_maps_api-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: apple_maps_api-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for apple_maps_api-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 599eeb981cde7021c1040d02fd28af213a41348ba96f0cd50d995e7e0964c326
MD5 41e16418ce92bc82b4bbda6b32b52f19
BLAKE2b-256 c21682c620736811763beebced606694b7743957165d812cba848359012e62c2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page