Metadata-Version: 2.4
Name: perigee
Version: 1.0.1
Summary: Dependency-free Python client for the Perigee Developer API
Project-URL: Homepage, https://perigeetides.com/developers
Project-URL: Documentation, https://perigeetides.com/developers
Project-URL: Support, https://perigeetides.com/help
Author-email: Cardin Labs <support@cardinlabs.com>
License-Expression: MIT
License-File: LICENSE
Keywords: coastal,decision-api,marine-weather,noaa,tides
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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
Provides-Extra: release
Requires-Dist: build==1.5.1; extra == 'release'
Requires-Dist: twine==6.2.0; extra == 'release'
Description-Content-Type: text/markdown

# Perigee Python SDK

The official, standard-library-only Python client for the
[Perigee Developer API](https://perigeetides.com/developers). It supports
Python 3.10+ and has no runtime dependencies.

## Install

```bash
python -m pip install perigee
```

## Quick start

Public station and tide-prediction calls do not require a key:

```python
from perigee import PerigeeClient

perigee = PerigeeClient()
stations = perigee.list_stations(q="Port Aransas", state="TX", limit=5)
predictions = perigee.tide_predictions("8775237", hours=24, interval="hilo")

print(stations.data)
print(predictions.request_id)
```

Authenticated decision calls use a server-side environment variable:

```python
import os
from perigee import PerigeeClient

perigee = PerigeeClient(api_key=os.environ["PERIGEE_API_KEY"])
result = perigee.best_window(
    stationId="9414290",
    activity="fishing",
    candidates=[
        {"localDate": "2026-07-10", "localTime": "06:00"},
        {"localDate": "2026-07-10", "localTime": "12:00"},
    ],
)

print(result.data["decision"])
print(result.request_id, result.monthly_remaining)
```

Other decision recipes follow the API's camel-case request fields:

```python
evaluation = perigee.evaluate_rules(
    stationId="9414290",
    activity="boating",
    localDate="2026-07-10",
    localTime="09:00",
    rules=[
        {
            "id": "confidence",
            "kind": "minimum_confidence",
            "minimum": "moderate",
        }
    ],
)

change = perigee.material_change(
    stationId="9414290",
    activity="boating",
    localDate="2026-07-10",
    localTime="09:00",
    baseline={
        "decisionId": "previous-decision-id",
        "evaluatedAt": "2026-07-09T12:00:00.000Z",
        "state": "normal",
        "confidence": "high",
        "reasonCodes": ["signal.tide"],
        "sources": [
            {
                "id": "tide-prediction",
                "freshness": "fresh",
                "sourceAt": "2026-07-09T11:00:00.000Z",
            }
        ],
    },
)
```

## Responses and errors

Every successful call returns `PerigeeResponse` with:

- `data`: the decoded API response
- `request_id`: the value to include in a support request
- `rate_remaining`: remaining short-window allowance, when present
- `monthly_remaining`: remaining monthly allowance, when present
- `quota_warning`: a proactive quota warning, when present

```python
from perigee import (
    PerigeeApiError,
    PerigeeProtocolError,
    PerigeeTransportError,
)

try:
    result = perigee.trip_health(
        stationId="9414290",
        activity="fishing",
        localDate="2026-07-10",
        localTime="07:00",
    )
except PerigeeApiError as error:
    print(error.status, error.code, error.request_id, error.retry_after_seconds)
except PerigeeTransportError as error:
    print(f"No response after {error.attempts} attempts")
except PerigeeProtocolError as error:
    print(error.status, error.request_id)
```

The client retries network failures, HTTP 429, and HTTP 5xx responses with
bounded exponential backoff. `Retry-After` is honored up to a ten-second
client-side cap. Authenticated cross-origin redirects are refused so an API
key cannot be forwarded to a different origin. Configure the limits when
constructing the client:

```python
perigee = PerigeeClient(
    api_key=os.environ["PERIGEE_API_KEY"],
    timeout_seconds=10,
    max_retries=2,
)
```

Do not embed an API key in browser code, a mobile binary, logs, or source
control. Use the request ID rather than credentials or full authorization
headers when asking for support.

See the [OpenAPI document](https://perigeetides.com/openapi.json) for the
complete response schemas and the
[developer status page](https://perigeetides.com/developer/status) during an
incident. Use the public [help and support surface](https://perigeetides.com/help)
for questions or issue reports.

## Release history

SDK releases follow semantic versioning and published registry versions are
immutable. See the packaged [changelog](./CHANGELOG.md) before upgrading.
