Skip to content

Repository files navigation

myaudi-api

Python client and REST API for the Audi Connect (myAudi) service. Check your vehicle status and execute remote actions via CLI or HTTP API.

Based on the open-source audiconnect/audi_connect_ha project.

Disclaimer: For personal and educational use only. Not affiliated with, endorsed by, or sponsored by Audi AG or Volkswagen Group. Use at your own risk — usage of the Audi Connect service is subject to Audi AG's terms of service.

⚠️ Rate limits: Audi's API is known to enforce aggressive rate limits (~6 requests/hour). Excessive polling will temporarily lock your account and the official myAudi app until the window resets. The default settings here are conservative (4h cache, background watcher disabled, 15 min minimum poll interval) — don't override them unless you know what you're doing.

Features

  • Full vehicle status (mileage, range, fuel level, oil level, AdBlue)
  • Quick status mode — locked, position, range in one glance
  • GPS position with Google Maps link (auto-open in browser)
  • Door, trunk, hood and window states
  • Charging data (EV/PHEV): SoC, power, remaining time, plug state
  • Remote lock / unlock (requires S-PIN) with confirmation
  • Remote climate control (start/stop, 16-30°C)
  • Auxiliary heater (start/stop, 10-60 min)
  • Trip data (short-term and long-term)
  • REST API (FastAPI) with Docker deployment and rate limiting
  • Watch mode — monitor changes and send webhook notifications
  • Action retry — automatic retry on network failures (lock, climate, heater)
  • Home Assistant integration via command_line sensor
  • OAuth token caching to avoid re-authenticating on every run
  • Interactive setup (python main.py setup)

Documentation

In-depth technical reference is in docs/:

Quick Start

git clone https://github.com/John6810/myaudi-api.git
cd myaudi-api
pip install -r requirements.txt
python main.py setup          # Interactive — creates .env file
python main.py status --brief # Quick check

CLI Usage

Setup

Run the interactive setup to create your .env file:

python main.py setup

Or copy the template:

cp .env.example .env

Or create .env manually:

AUDI_USERNAME=your.email@example.com
AUDI_PASSWORD=your_password
AUDI_COUNTRY=DE
AUDI_SPIN=1234
AUDI_API_LEVEL=1
AUDI_DEFAULT_VIN=WAUXXXXXXXXXXXXX
AUDI_WEBHOOK_URL=https://n8n.example.com/webhook/audi

Configuration

Variable Description Default
AUDI_USERNAME myAudi account email (required)
AUDI_PASSWORD Password (required)
AUDI_COUNTRY Country code (DE, FR, US, etc.) DE
AUDI_SPIN S-PIN for lock/unlock (optional)
AUDI_API_LEVEL 0 = legacy MBB, 1 = new CARIAD API 1
AUDI_DEFAULT_VIN Default VIN — skip --vin for single-vehicle users (optional)
AUDI_WEBHOOK_URL Webhook URL for state change notifications (optional)
AUDI_WEBHOOK_SECRET If set, webhooks are signed with HMAC-SHA256 in the X-Audi-Signature header (optional)
AUDI_WATCH_INTERVAL Background poll interval in seconds (API server only) 0 (disabled)
AUDI_CACHE_TTL Data cache TTL in seconds 14400 (4h)
AUDI_API_KEY Required header X-API-Key on all endpoints except /health, /ready, /metrics. Set to a strong random token. (optional but strongly recommended)

Commands

# Quick status (locked, position, range)
python main.py status --brief

# Full vehicle status (with debug logs)
python main.py status -v

# GPS position (opens in browser)
python main.py position --open-maps

# Lock with confirmation (waits 5s and checks)
python main.py lock --confirm

# Unlock
python main.py unlock --confirm

# Climate control
python main.py climate-start --temp 22
python main.py climate-stop

# Auxiliary heater
python main.py heater-start --duration 30
python main.py heater-stop

# Watch mode — monitor changes, send webhooks
python main.py watch --interval 900

# Target a specific VIN (if multiple vehicles)
python main.py status --vin WAUXXXXXXXXXXXXX

REST API

Run locally

uvicorn server:app --host 0.0.0.0 --port 8000

Run with Docker

docker build -t audi-connect .
docker run -p 8000:8000 \
  -e AUDI_USERNAME="your.email@example.com" \
  -e AUDI_PASSWORD="your_password" \
  -e AUDI_COUNTRY="DE" \
  -e AUDI_SPIN="1234" \
  -e AUDI_API_LEVEL="1" \
  audi-connect

Kubernetes

kubectl create secret generic audi-credentials \
  -n myaudi-api \
  --from-literal=AUDI_USERNAME="your.email@example.com" \
  --from-literal=AUDI_PASSWORD="your_password" \
  --from-literal=AUDI_COUNTRY="DE" \
  --from-literal=AUDI_SPIN="1234" \
  --from-literal=AUDI_API_LEVEL="1"

Authentication

All endpoints except /health require an X-API-Key header.

Set AUDI_API_KEY server-side (in the K8s secret or your .env):

# Generate a strong key
python -c "import secrets; print(secrets.token_urlsafe(32))"

Add it to your .env along with the other required vars:

AUDI_USERNAME=your.email@example.com
AUDI_PASSWORD=your_password
AUDI_COUNTRY=DE
AUDI_SPIN=1234
AUDI_API_LEVEL=1
AUDI_API_KEY=<generated_key>

Send the same key as a header on every call:

curl -H "X-API-Key: your_key_here" http://localhost:8000/brief

Without the header (or with a wrong key), endpoints return 401. If AUDI_API_KEY is unset on the server, all protected endpoints return 503.

Observability

Metrics

GET /metrics exposes Prometheus metrics in text format. In addition to the standard FastAPI HTTP metrics, four custom business metrics are emitted:

  • audi_auth_refresh_total{result="success|failure"} — login/refresh attempts
  • audi_cache_operation_total{operation="hit|miss|invalidate"} — cache events
  • audi_action_total{action, result} — remote actions counts
  • audi_backend_request_duration_seconds{endpoint} — upstream Audi latency

The /metrics, /health and /ready endpoints are excluded from HTTP request metrics to avoid kubelet probes drowning the signal.

Probes

  • GET /health — liveness. Returns 200 even when Audi Connect is degraded (don't kill the pod just because upstream is down).
  • GET /ready — readiness. Returns 503 until the service has successfully authenticated to Audi Connect.

Request correlation

Every request gets an X-Request-ID header (provided by the client if present, otherwise generated). The same value is included in log records under [rid=...] so requests can be correlated end-to-end in Loki/Grafana.

Endpoints

Method Path Auth Description
GET /health public Liveness check + cache info. 200 even when Audi is degraded.
GET /ready public Readiness probe. 503 until authenticated to Audi Connect.
GET /metrics public Prometheus metrics in text format.
GET /vehicles X-API-Key List vehicles
GET /status X-API-Key Full vehicle status (optional ?vin=)
GET /brief X-API-Key Quick status: locked, position, range
GET /position X-API-Key GPS position (optional ?vin=)
POST /{vin}/lock X-API-Key Lock vehicle (?confirm=true to verify)
POST /{vin}/unlock X-API-Key Unlock vehicle (?confirm=true to verify)
POST /{vin}/climate/start X-API-Key Start climate (?temp=21&confirm=true)
POST /{vin}/climate/stop X-API-Key Stop climate
POST /{vin}/heater/start X-API-Key Start heater (?duration=30&confirm=true)
POST /{vin}/heater/stop X-API-Key Stop heater

Action endpoints accept ?confirm=true to wait 5 seconds after the action, re-fetch vehicle data, and return the updated status. Without it, the response is immediate ("status": "sent").

Cache is automatically invalidated after any action so the next GET /status reflects the change.

Rate limiting: read endpoints allow 30 requests/min, action endpoints allow 5 requests/min. Exceeding returns HTTP 429. The /health, /ready and /metrics endpoints are not rate-limited and don't require X-API-Key — they are intended for kubelet probes and Prometheus scraping.

Example responses

curl http://localhost:8000/brief
{
  "vehicles": [{
    "vehicle": "My Audi",
    "locked": "Locked",
    "position": "50.123, 4.456",
    "maps": "https://www.google.com/maps?q=50.123,4.456",
    "range": "200 km",
    "battery": "51%"
  }]
}
curl http://localhost:8000/status
{
  "count": 1,
  "vehicles": [{
    "vin": "WAUXXXXX",
    "mileage": "4,391 km",
    "range": "200 km",
    "battery_soc": "51%",
    "charging": "notReadyForCharging",
    "doors_trunk": "Locked",
    "windows": "Closed",
    "climatisation": "off"
  }]
}
curl -X POST "http://localhost:8000/WAUXXXXX/lock?confirm=true"
{
  "status": "confirmed",
  "action": "lock",
  "vin": "WAUXXXXX",
  "vehicle_status": {"doors_trunk": "Locked", "windows": "Closed", "range": "200 km"}
}

Webhooks

Set AUDI_WEBHOOK_URL and AUDI_WATCH_INTERVAL to enable background monitoring. The API server will poll vehicle data at the configured interval and POST state changes:

{
  "event": "state_change",
  "vin": "WAUXXXXX",
  "title": "My Audi",
  "changes": {
    "locked": {"old": "Locked", "new": "Closed"}
  },
  "state": {"vehicle": "My Audi", "locked": "Closed", "position": "50.123, 4.456", "range": "200 km"},
  "timestamp": "2026-04-12T22:30:00+02:00"
}

Works with n8n, Home Assistant webhooks, Discord webhooks, or any HTTP endpoint.

Webhook signing (optional)

Set AUDI_WEBHOOK_SECRET to enable HMAC-SHA256 signing. Each request will include an X-Audi-Signature: sha256=<hex> header computed over the raw request body. The receiver must recompute the HMAC over the raw body and reject mismatches.

Example n8n verification (Function node — webhook node must be configured to use raw body, otherwise n8n re-serialises the payload and the signature won't match):

const crypto = require('crypto');
const secret = $env.AUDI_WEBHOOK_SECRET;
const sig = $request.headers['x-audi-signature'];
const expected = 'sha256=' + crypto
  .createHmac('sha256', secret)
  .update($request.body.raw)
  .digest('hex');
if (!sig || !crypto.timingSafeEqual(
    Buffer.from(sig), Buffer.from(expected))) {
  throw new Error('Invalid signature');
}
return items;

Home Assistant Integration

The ha_sensor.py script outputs vehicle data as JSON to stdout, compatible with Home Assistant's command_line sensor:

command_line:
  - sensor:
      name: "Audi Connect"
      command: "python3 /config/scripts/myaudi-api/ha_sensor.py"
      value_template: "{{ value_json.range }}"
      json_attributes:
        - vin
        - model
        - mileage
        - range
        - battery_soc
        - charging_state
        - plug_state
        - latitude
        - longitude
        - doors_locked
        - windows_closed
        - climatisation
      scan_interval: 300

Architecture

myaudi-api/
  server.py                # FastAPI REST API (cache, webhooks, confirm)
  main.py                  # CLI (setup, status, watch, actions)
  ha_sensor.py             # Home Assistant script
  Dockerfile
  requirements.txt
  audi_connect/
    oauth.py               # 13-step OAuth2/OIDC login flow
    oauth_state.py         # Frozen OAuthState dataclass (10 token fields, from_dict / to_dict / with_refresh)
    auth.py                # Token coordinator (delegates to oauth.py / client / actions)
    endpoints.py           # cariad_url() helper + AudiEndpoints (URL building + home-region cache)
    client.py              # Read-only API calls (status, position, trips)
    actions.py             # Remote actions (lock, climate, heater)
    api.py                 # Low-level HTTP client (retry, timeout)
    connection.py          # Shared connection helpers
    vehicle.py             # AudiVehicle (properties, validation, brief/dashboard, idempotent-only retry)
    watcher.py             # Shared watch logic (diff_states, check_vehicles callbacks)
    models.py              # Response parsing + LockState/DoorState/WindowState enums
    utils.py               # Utility functions
    exceptions.py          # Custom exceptions
    token_store.py         # Token persistence (restricted file permissions)
    logging_utils.py       # redact() + RedactingFilter (masks bearer tokens, OAuth JSON, X-QMAuth, emails in logs)
  tests/                   # 183 tests (pytest + pytest-asyncio + aioresponses)
    test_vehicle.py        # is_moving, parallel fetch, validation, brief, idempotent retry policy
    test_actions.py        # S-PIN hash, climate (CARIAD + legacy), heater
    test_auth.py           # Token restore, login (returns vehicle list), refresh, OAuth helpers
    test_integration.py    # Integration tests (real HTTP stack, mocked network)
    test_watcher.py        # State diff, vehicle polling callbacks
    test_models.py         # Response parsing, enums, indexed get_field/get_state
    test_cli.py            # Error formatting, VIN resolution
    test_utils.py          # Utility functions
    test_token_store.py    # OAuthState round-trip persistence
    test_exceptions.py     # Exception hierarchy
    test_endpoints.py      # cariad_url + AudiEndpoints home-region cache
    test_logging_utils.py  # redact patterns + RedactingFilter
    test_observability.py  # /metrics, /ready, X-Request-ID middleware
    test_api_auth.py       # X-API-Key dependency on protected endpoints
  .github/workflows/
    build.yml              # CI/CD: Docker build + GHCR push + GitOps update

Tests

python -m pytest tests/ -v

183 tests covering: authentication flow, OAuth helpers, OAuthState dataclass + token persistence, vehicle data parsing, action validation, idempotent-only retry policy, parallel fetching, error formatting, enums, state watcher, integration tests with mocked HTTP, URL building / home-region cache, log secret redaction, X-API-Key dependency, /metrics + /ready + request-id middleware.

How It Works

Authentication implements the OAuth2/OIDC flow used by the myAudi service in 13 steps:

  1. Fetch Audi market configuration
  2. OpenID Connect discovery
  3. PKCE challenge generation (S256)
  4. Email + password submission via HTML forms
  5. Exchange authorization code for an IDK bearer token
  6. Obtain the AZS (Audi) token
  7. Register MBB OAuth client (VW Group)
  8. Obtain and refresh the MBB token

Three tokens are managed in parallel:

  • IDK/CARIAD: for the new vehicle API
  • AZS: for the Audi GraphQL API (vehicle list)
  • MBB/VW: for the legacy API (trips, lock/unlock)

Tokens are cached locally (~/.audi_connect_tokens.json, 1h TTL, restricted file permissions on Unix) to skip the full login flow on subsequent runs. The API server refreshes tokens automatically every 45 minutes.

Dependencies

  • aiohttp - Async HTTP client
  • beautifulsoup4 - HTML parsing (authentication flow)
  • python-dotenv - .env file loading
  • certifi - CA bundle for SSL validation
  • tenacity - Retry with exponential backoff
  • fastapi - REST API framework
  • uvicorn - ASGI server
  • slowapi - Rate limiting
  • prometheus-fastapi-instrumentator - Standard FastAPI HTTP metrics + custom business metrics on /metrics
  • pytest + pytest-asyncio + aioresponses - Testing

License

MIT License. See LICENSE for details.

Usage of the Audi Connect API is subject to Audi AG's terms of service.

About

Python client & REST API for Audi Connect (myAudi) — vehicle status, GPS position, remote lock/climate/heater. 13-step OAuth2, FastAPI, 145 tests.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages