Metadata-Version: 2.5
Name: altitude-sdk
Version: 2.0.0
Summary: Python client SDK for the Geotab Altitude APIs
Project-URL: Homepage, https://www.geotab.com
Project-URL: Documentation, https://developers.geotab.com
Author: Geotab
License: Copyright (c) 2026 Geotab Inc. All rights reserved.
        
        PROPRIETARY AND CONFIDENTIAL
        
        This software and its source code are the proprietary and confidential property
        of Geotab Inc. ("Geotab"). The software is licensed, not sold.
        
        Subject to the terms of a separate written agreement between you and Geotab, you
        are granted a non-exclusive, non-transferable, revocable license to install and
        use this software solely for its intended purpose of accessing the Geotab
        Altitude APIs.
        
        You may NOT, without the prior written permission of Geotab:
          - copy, modify, or create derivative works of the software;
          - distribute, sublicense, lease, rent, or otherwise transfer the software;
          - reverse engineer, decompile, or disassemble the software except to the
            extent expressly permitted by applicable law.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
        FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL GEOTAB BE
        LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF
        CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
        SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
License-File: LICENSE
Keywords: altitude,api,geotab,sdk,telematics
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: typing-extensions>=4.6
Description-Content-Type: text/markdown

# altitude-sdk

altitude-sdk is a lightweight Python client for the Geotab Altitude APIs. It is designed
to make getting started quick and easy, handling authentication, async job submission and
polling, and result pagination so you can focus on the data rather than the plumbing.

Requires Python 3.10+.

## Contents

- [Installation](#installation)
- [Quick start](#quick-start)
- [Two calling patterns](#two-calling-patterns)
- [Working with job ids](#working-with-job-ids)
- [Client modules](#client-modules)
- [Module reference](#module-reference)
- [Examples](#examples)
- [Resuming with an id](#resuming-with-an-id)

## Installation

```bash
pip install altitude-sdk
```

## Quick start

```python
from altitude_sdk import AltitudeClient

# Authenticate with your API key; sent as `Authorization: Bearer <api_key>`.
client = AltitudeClient(api_key="your-api-key")

industries = client.filters.get_industries()
```

`AltitudeClient` accepts a few optional settings:

```python
import httpx
from altitude_sdk import AltitudeClient

client = AltitudeClient(
    api_key="your-api-key",
    timeout=60.0,                                 # seconds, or an httpx.Timeout
)

# Use as a context manager to close the underlying HTTP client automatically.
with AltitudeClient(api_key="your-api-key") as client:
    industries = client.filters.get_industries()
```

## Two calling patterns

Every method on the client is one of two kinds:

- **Job process** — long-running analytics. The call returns a `PagedWorkflow` handle
  rather than data. Use `.all()` to submit, poll to completion, paginate, and return all
  rows in one step, or drive it manually with `.run()`, `.status()`, `.results()`,
  `.pages()`, and `.cancel()`. A few workflows also expose `.time_series_results()`.
- **Direct API** — synchronous reference/CRUD calls. The method returns the data
  immediately, no workflow involved.

The **Type** column in each table below tells you which kind a method is.

## Working with job ids

Every job-process method submits a job that the server identifies by an id. Hold on to that
id and you can come back to the job later — from a different process, or after your program
restarts — without re-running the analysis.

Keep the workflow in a variable instead of chaining `.all()` onto the call. `.all()` waits for
the job to finish, and afterwards `wf.id` holds the id of the job that produced those rows:

```python
wf = client.stop_analytics.rda(params)   # keep the handle
rows = wf.all()                          # submit → poll to completion → paginate
print(wf.id)                             # "its_123" — save this to resume later
```

This is the same for every job-process method — every method marked **Job** in the tables
below:

```python
poi = client.poi.analytics(params)
rows = poi.all()
print(poi.id)

speed = client.traffic.speed_summary(params)
rows = speed.all()
print(speed.id)
```

`wf.id` is `None` until the job is submitted. If you want it before the results are ready, use
`.run()`, which submits without waiting:

```python
wf = client.stop_analytics.rda(params)
wf.run()          # submit, non-blocking — sets wf.id right away
print(wf.id)      # "its_123"
```

`.status()` also carries the id alongside the current state:

```python
wf.status()   # {"id": "its_123", "status": "RUNNING", "links": {...}}
```

Once you have an id, see [Resuming with an id](#resuming-with-an-id).

## Client modules

`AltitudeClient` exposes these module clients as attributes:

| Module                                              | Attribute                   | Covers                                                                   |
| --------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------ |
| [Jobs](#jobs)                                       | `client.jobs`               | Check status of / cancel any submitted job                               |
| [AADT](#aadt)                                       | `client.aadt`               | Annual average daily traffic jobs                                        |
| [Filters](#filters)                                 | `client.filters`            | Reference filter options (industries, NAICS, vehicle classes, vocations) |
| [Database](#database)                               | `client.database`           | Database configuration                                                   |
| [Expansion factors](#expansion-factors)             | `client.expansion_factors`  | Expansion factor list                                                    |
| [Analyses](#analyses)                               | `client.analyses`           | Analysis parameters, zones, and data-quality dates                       |
| [Origin / destination](#origin--destination)        | `client.origin_destination` | OD matrices (open, closed, corridor), route and segment analysis         |
| [POI](#poi)                                         | `client.poi`                | Points-of-interest analytics, summaries, and locations                   |
| [Regional travel metrics](#regional-travel-metrics) | `client.rtm`                | VDT, fuel economy, idle, demand generation, observed counts              |
| [Stop analytics](#stop-analytics)                   | `client.stop_analytics`     | Regional domicile, fuel point, and stop-event analytics                  |
| [Traffic](#traffic)                                 | `client.traffic`            | Speed and harsh-event traffic analytics                                  |
| [Zones](#zones)                                     | `client.zones`              | Zone lookups, custom zones, and sub-types                                |

## Module reference

### Jobs

`client.jobs`

| Method               | Type   | Description                       |
| -------------------- | ------ | --------------------------------- |
| `get_job_status(id)` | Direct | Get the status of a submitted job |
| `cancel_job(id)`     | Direct | Cancel a running job              |

### AADT

`client.aadt`

| Method                 | Type | Description                                    |
| ---------------------- | ---- | ---------------------------------------------- |
| `modeled_aadt(params)` | Job  | Start modeled annual average daily traffic job |

### Filters

`client.filters`

| Method                     | Type   | Description                         |
| -------------------------- | ------ | ----------------------------------- |
| `get_industries()`         | Direct | Get grouped industry filter options |
| `get_naics(...)`           | Direct | Get raw NAICS code list             |
| `get_vehicle_classes(...)` | Direct | Get vehicle class filter options    |
| `get_vocations()`          | Direct | Get vocation filter options         |

### Database

`client.database`

| Method         | Type   | Description                |
| -------------- | ------ | -------------------------- |
| `get_config()` | Direct | Get database configuration |

### Expansion factors

`client.expansion_factors`

| Method                       | Type   | Description            |
| ---------------------------- | ------ | ---------------------- |
| `get_expansion_factors(...)` | Direct | List expansion factors |

### Analyses

`client.analyses`

| Method                      | Type   | Description                               |
| --------------------------- | ------ | ----------------------------------------- |
| `get_analysis_params(id)`   | Direct | Get parameters for an analysis            |
| `get_analysis_zones(id)`    | Direct | Get zone GeoJSON features for an analysis |
| `get_last_processed_date()` | Direct | Get the last processed date               |

### Origin / destination

`client.origin_destination`

| Method                    | Type | Description                                                  |
| ------------------------- | ---- | ------------------------------------------------------------ |
| `open_matrix(params)`     | Job  | Start open OD matrix job (also `.time_series_results()`)     |
| `closed_matrix(params)`   | Job  | Start closed OD matrix job (also `.time_series_results()`)   |
| `corridor_matrix(params)` | Job  | Start corridor OD matrix job (also `.time_series_results()`) |
| `route(params)`           | Job  | Start OD route analysis job                                  |
| `segment(params)`         | Job  | Start OD segment analysis job                                |

### POI

`client.poi`

| Method              | Type | Description                                             |
| ------------------- | ---- | ------------------------------------------------------- |
| `analytics(params)` | Job  | Start POI analytics job (also `.time_series_results()`) |
| `summary(params)`   | Job  | Start POI summary job                                   |
| `locations(params)` | Job  | Start point of interest job                             |

### Regional travel metrics

`client.rtm`

| Method                      | Type | Description                                                                 |
| --------------------------- | ---- | --------------------------------------------------------------------------- |
| `demand_generation(params)` | Job  | Start demand generation job (also `.time_series_results()`)                 |
| `fuel_economy(params)`      | Job  | Start fuel economy job                                                      |
| `idle_metrics(params)`      | Job  | Start idle metrics job (also `.time_series_results()`)                      |
| `modeled_vdt(params)`       | Job  | Start modeled vehicle distance traveled job (also `.time_series_results()`) |
| `observed_counts(params)`   | Job  | Start observed counts job (also `.time_series_results()`)                   |
| `vdt(params)`               | Job  | Start vehicle distance traveled job (also `.time_series_results()`)         |

### Stop analytics

`client.stop_analytics`

| Method                         | Type | Description                                                    |
| ------------------------------ | ---- | -------------------------------------------------------------- |
| `fuel_point_analytics(params)` | Job  | Start Fuel Point Analytics job (also `.time_series_results()`) |
| `rda(params)`                  | Job  | Start Regional Domicile Analytics job                          |
| `stop_events(params)`          | Job  | Start stop events job                                          |

### Traffic

`client.traffic`

| Method                             | Type | Description                        |
| ---------------------------------- | ---- | ---------------------------------- |
| `harsh_events_per_segment(params)` | Job  | Start harsh events per segment job |
| `road_reverse_lookup(params)`      | Job  | Start road reverse lookup job      |
| `speed_map_metrics(params)`        | Job  | Start speed map metrics job        |
| `speed_per_segment(params)`        | Job  | Start speed per segment job        |
| `speed_summary(params)`            | Job  | Start speed summary job            |
| `speed_trend(params)`              | Job  | Start speed trend job              |

### Zones

`client.zones`

| Method                              | Type   | Description                          |
| ----------------------------------- | ------ | ------------------------------------ |
| `by_hierarchy(params)`              | Job    | Start zones by hierarchy job         |
| `by_ids(params)`                    | Job    | Start zone data fetch by IDs         |
| `by_radius(params)`                 | Job    | Start zones by radius job            |
| `by_sub_type(params)`               | Job    | Start custom zones by sub-type fetch |
| `contained_zones(params)`           | Job    | Start contained zones job            |
| `road_segments(params)`             | Job    | Start road segments job              |
| `batch_update_custom_zones(params)` | Job    | Batch update custom zones            |
| `create_custom_zone(params)`        | Direct | Create custom zone                   |
| `create_sub_type(params)`           | Direct | Create custom zone sub-type          |
| `list_sub_types()`                  | Direct | List custom zone sub-types           |
| `update_sub_type(id, params)`       | Direct | Update custom zone sub-type          |

## Examples

### Job process method

Job-process methods return a `PagedWorkflow`. The simplest path is `.all()`, which
submits the job, polls until it finishes, paginates, and returns every row:

```python
from altitude_sdk import AltitudeClient

client = AltitudeClient(api_key="your-api-key")

params = {
    "zones": [{"code": "32007", "iso_3166_2": "US-NV", "type": "County"}],
    "isMetric": False,
    "dateFrom": "2025-03-01",
    "dateTo": "2025-03-05",
}

# All-in-one: submit → poll to completion → paginate → list of results
rows = client.stop_analytics.rda(params).all()
```

For more control, drive the workflow step by step:

```python
import time

wf = client.stop_analytics.rda(params)
wf.run()                                    # submit the job (non-blocking); sets wf.id
while wf.status()["status"] != "DONE":      # poll until the job finishes
    time.sleep(5)
rows = wf.results()                         # fetch the results once DONE
```

### Direct API method

Direct methods return data immediately — no workflow, no polling:

```python
from altitude_sdk import AltitudeClient

client = AltitudeClient(api_key="your-api-key")

industries = client.filters.get_industries()
naics = client.filters.get_naics(min_naics_level=2, max_naics_level=2)
```

## Resuming with an id

Pass `id=` to the **same method that started the job** — it knows where that job's results
live. Every job-process method accepts it:

```python
# Later — different process, same job. Nothing is re-submitted.
handle = client.stop_analytics.rda(id="its_123")
if handle.status()["status"] == "DONE":
    rows = handle.results()
```

Two rules apply to an id handle:

- Pass exactly one of `params` or `id` — passing both, or neither, raises
  `AltitudeWorkflowError`.
- It retrieves, it does not submit. `.results()`, `.pages()`, `.status()`, and
  `.time_series_results()` work; `.all()` and `.cancel()` raise `AltitudeWorkflowError`,
  because there is nothing left to start or stop.
