Metadata-Version: 2.5
Name: airflow-provider-lexio
Version: 0.1.0
Summary: Apache Airflow provider for the Lexio Rent API: hook, operators and an event sensor for car and van rental data (fleet, rentals, customers, payments, maintenance).
Project-URL: Homepage, https://lexio.rent/logiciel-location-voiture
Project-URL: Documentation, https://github.com/lexio-rent-git/airflow-provider-lexio#readme
Project-URL: API reference, https://docs.lexio.rent
Project-URL: Source, https://github.com/lexio-rent-git/airflow-provider-lexio
Project-URL: Issues, https://github.com/lexio-rent-git/airflow-provider-lexio/issues
Author-email: Lexio Rent <contact@lexio.rent>
License-Expression: MIT
License-File: LICENSE
Keywords: airflow,airflow-provider,car-rental,fleet-management,lexio,lexio-rent,rental-software
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Apache Airflow
Classifier: Framework :: Apache Airflow :: Provider
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: apache-airflow>=2.9
Requires-Dist: lexio-rent>=0.1.0
Provides-Extra: test
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# Apache Airflow provider for Lexio Rent

[![PyPI](https://img.shields.io/pypi/v/airflow-provider-lexio.svg)](https://pypi.org/project/airflow-provider-lexio/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

`airflow-provider-lexio` connects Apache Airflow to the [Lexio Rent API](https://docs.lexio.rent). Use it to move car and van rental data (fleet, rentals, customers, quotes, payments, maintenance) into a warehouse, a BI tool or an accounting system, on a schedule.

<a href="https://lexio.rent/logiciel-location-voiture">Lexio Rent</a> is rental management software for professional car, van and two-wheeler rental companies: planning, contracts, check-in/check-out inspections, deposits and fleet maintenance.

| Component | What it does |
|---|---|
| `LexioHook` | Builds an authenticated client from an Airflow connection. Every one of the 93 API operations is available through `hook.client`. |
| `LexioOperator` | Calls any operation (`resource` + `method`) and pushes the JSON response to XCom. |
| `LexioListOperator` | Exports a full list endpoint, following pagination, to XCom or to a JSON Lines file. |
| `LexioEventSensor` | Waits for `rental.created` / `rental.updated` / `rental.cancelled` / `rental.deleted` events. The API has no webhooks, so the sensor reads the event feed and keeps its cursor in an Airflow Variable. |

Works with Airflow 2.9+ and Airflow 3. Built on the [`lexio-rent`](https://pypi.org/project/lexio-rent/) Python client.

## Installation

```bash
pip install airflow-provider-lexio
```

## Connection

The Lexio API needs an API key, created in Lexio under **Settings → Developer → API tokens**. Keys start with `lck_`. API access is part of the Business plan, and there is no sandbox: test against a dedicated organization.

Create a connection of type **Lexio Rent** (id `lexio_default` by default):

| Field | Value |
|---|---|
| Password | your `lck_...` API key |
| Host | optional, overrides `https://api.lexio.rent/api/external/v1` |

Or with an environment variable:

```bash
export AIRFLOW_CONN_LEXIO_DEFAULT='{"conn_type": "lexio", "password": "lck_..."}'
```

The **Test** button in the Airflow UI calls `GET /organization` and shows the organization name.

## Usage

```python
from lexio_provider.operators.lexio import LexioListOperator, LexioOperator
from lexio_provider.sensors.lexio import LexioEventSensor

# Whole active fleet, written as JSON Lines
export_fleet = LexioListOperator(
    task_id="export_fleet",
    resource="vehicles",
    filters={"is_archived": False},
    output_path="/data/lexio/vehicles_{{ ds_nodash }}.jsonl",
)

# One operation: GET /rentals/{rentalId}
get_rental = LexioOperator(
    task_id="get_rental",
    resource="rentals",
    method="get",
    args=["{{ params.rental_id }}"],
)

# Wait for new or changed rentals
new_rentals = LexioEventSensor(
    task_id="wait_for_rentals",
    event_types=["rental.created", "rental.updated"],
    mode="reschedule",
    poke_interval=60,
)
```

`resource` and `method` follow the `lexio-rent` client: `vehicles.list`, `rentals.get`, `rentals.pick_up`, `customers.create`, `maintenance_records.list`, `events.list`... Query filters are written in snake_case (`is_archived=False` is sent as `isArchived=false`); JSON bodies keep the API field names.

Inside a `@task`, use the hook directly:

```python
from lexio_provider.hooks.lexio import LexioHook

hook = LexioHook()
for rental in hook.iter_all("rentals", status="RESERVED,IN_PROGRESS"):
    ...
```

A complete DAG (event sensor, then re-read of the changed rentals, then a fleet export) is in [`example_dags/lexio_rentals_sync.py`](example_dags/lexio_rentals_sync.py).

### How the event sensor works

- First run: the feed starts at `start="LATEST"` (now), or `"EARLIEST"` (the last 29 days).
- Each poke reads every page from the stored cursor and saves the new cursor in the Variable `lexio_events_cursor__<conn id>` (configurable with `cursor_variable`).
- When at least one event matches, the sensor succeeds and returns the events through XCom. Events are thin (`id`, `type`, `occurredAt`, `resource.id`): read the rental again for its current state.
- The cursor moves forward on every poke, so delivery to downstream tasks is at most once. Cursors expire after 30 days (`410 CURSOR_EXPIRED`); delete the Variable to start again.

### Retries, idempotency and errors

The underlying client retries 429 and 5xx responses on reads and on idempotent writes, honouring `Retry-After`, and sends an `Idempotency-Key` on writes that need one, so an Airflow retry never books a vehicle twice. API errors are raised as typed exceptions (`NotFoundError`, `ConflictError`, `RateLimitError`...) with the Lexio `code`, `detail` and `request_id`, which show up in the task log.

## Development

```bash
pip install -e ".[test]"
pytest
```

Tests use a mocked HTTP transport; they need no API key.

## About

This provider is maintained by the team behind <a href="https://lexio.rent/logiciel-location-voiture">Lexio Rent, car rental management software</a>. A typical pipeline reconciles rental deposits in the warehouse; for the paperwork side, Lexio also publishes a free <a href="https://lexio.rent/outils/decompte-restitution-caution-location">security deposit refund statement generator</a> (in French) that itemises deductions when a vehicle is returned.

- API documentation: <https://docs.lexio.rent>
- OpenAPI specification: <https://docs.lexio.rent/openapi.json>
- Python client: <https://github.com/lexio-rent-git/lexio-python>
- Contact: contact@lexio.rent

MIT License.
