# 3.5 Python Examples

The following examples use only the Python standard library. No third-party HTTP client is required.

***

## Authentication — Get a Bearer Token

```python
import json
import urllib.request
import urllib.error


def get_token(base_url: str, pat: str) -> str:
    payload = json.dumps({"token": pat}).encode()
    req = urllib.request.Request(
        f"{base_url}/api/v1/jsonair/auth/token",
        data=payload,
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(req) as resp:
        body = json.loads(resp.read())
    return body["access_token"]
```

***

## Fetch Configuration Data

```python
def get_config(
    base_url: str,
    token: str,
    config_type: str,
    config_name: str,
    decode: bool = False,
) -> str:
    payload = json.dumps(
        {"type": config_type, "name": config_name, "decode": decode}
    ).encode()
    req = urllib.request.Request(
        f"{base_url}/api/v1/jsonair/config",
        data=payload,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        method="GET",
    )
    try:
        with urllib.request.urlopen(req) as resp:
            return resp.read().decode()
    except urllib.error.HTTPError as exc:
        if exc.code == 401:
            raise PermissionError("token expired") from exc
        raise
```

***

## Putting It Together — Poll with Re-Authentication

This pattern mirrors what the JSONAir agent does: authenticate once, poll on an interval, and re-authenticate automatically when the JWT expires.

```python
import base64
import time


BASE_URL = "https://jsonair.example.com"
PAT = "your-plain-text-pat"
CONFIG_TYPE = "myapp"
CONFIG_NAME = "prod.yaml"
INTERVAL = 30  # seconds


def main() -> None:
    token = get_token(BASE_URL, PAT)

    while True:
        try:
            raw = get_config(BASE_URL, token, CONFIG_TYPE, CONFIG_NAME, decode=False)
        except PermissionError:
            print("JWT expired, re-authenticating...")
            token = get_token(BASE_URL, PAT)
            raw = get_config(BASE_URL, token, CONFIG_TYPE, CONFIG_NAME, decode=False)

        config = base64.b64decode(raw).decode()
        print(f"config: {config}")
        time.sleep(INTERVAL)


if __name__ == "__main__":
    main()
```

***

## Fetch the Reload Key

```python
def get_reload(base_url: str, token: str, config_type: str, config_name: str) -> str:
    payload = json.dumps({"type": config_type, "name": config_name}).encode()
    req = urllib.request.Request(
        f"{base_url}/api/v1/jsonair/reload",
        data=payload,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        method="GET",
    )
    with urllib.request.urlopen(req) as resp:
        body = json.loads(resp.read())
    return body["reload"]
```

***

## Fetch the Debug Level

```python
def get_debug(base_url: str, token: str, config_type: str, config_name: str) -> str:
    payload = json.dumps({"type": config_type, "name": config_name}).encode()
    req = urllib.request.Request(
        f"{base_url}/api/v1/jsonair/debug",
        data=payload,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        method="GET",
    )
    with urllib.request.urlopen(req) as resp:
        body = json.loads(resp.read())
    return body["debug"]
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.k9.io/key9-identity/jsonair/3-using-the-api/3.5-python-examples.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
