# ezeas Client SDK (Python)

Minimal async client for the ezeas Client API using HS256 JWT.

This SDK is intended for backend integrations (Python 3.9+).  
It handles:

- Generating and caching short-lived JWT access tokens
- Sending authenticated requests to the ezeas Client API
- Simple error handling for business errors (4xx) and internal errors (5xx)

**Learn more:**  
https://www.ezeas.com/sdk/python

---

## Installation

```bash
pip install ezeas-client
```

> Requires Python **3.9+**.

---

## Quick start

```python
import asyncio
from ezeas_client import EzeasClient

async def main() -> None:
    client = EzeasClient(
        client_id="your-client-id",
        client_secret="your-client-secret",
        domain_key="domain-key",
        environment="live",       # or: "sandbox"
    )

    async with client:
        # Create / upsert contact
        contact_result = await client.contact.create({
            "external_id": "EXT-123",
            "employee_number": "EMP-001",
            "first_name": "Jane",
            "last_name": "Doe",
            "mobile": "+61400000000",
            "email": "jane.doe@example.com",
            "tenure_date": "2025-11-01",
            "role": "Talent", # Optional default to `Candidate`
        })
        print("Contact:", contact_result)

        # Submit timesheet
        timesheet_result = await client.timesheet.create({
            "job_code": "JOB-001",
            "timesheet_entries": [
                {
                    "date": "2025-11-01",
                    "hours_ordinary": 8.0,
                    "hours_time_and_half": 2.0,
                    "hours_double_time": 0.0,
                },
                {
                    "date": "2025-11-02",
                    "hours_ordinary": 7.5,
                    "hours_time_and_half": 0.0,
                    "hours_double_time": 0.0,
                },
            ],
        })
        print("Timesheet:", timesheet_result)

if __name__ == "__main__":
    asyncio.run(main())
```

---

## Types (logical shapes)

```python
from typing import List, Optional, TypedDict, Literal

DateString = str  # ISO date string "YYYY-MM-DD"

Role = Literal["Talent", "Candidate"]

class ContactInput(TypedDict, total=False):
    external_id: str
    employee_number: Optional[str]
    first_name: Optional[str]
    last_name: str
    mobile: Optional[str]
    email: str
    tenure_date: Optional[DateString]
    role: Optional[Role]

class TimesheetEntry(TypedDict):
    date: DateString
    hours_ordinary: float
    hours_time_and_half: float
    hours_double_time: float

class TimesheetInput(TypedDict):
    job_code: str
    timesheet_entries: List[TimesheetEntry]
```

---

## Error handling

- **2xx** → parsed JSON returned
- **4xx** → raises `Exception` with backend payload
- **5xx** → raises `Exception("Internal server error <status>: <body>")`

Wrap calls in your own `try/except` as needed.

---

## Token format (HS256 JWT)

Payload includes:

- `sub`: client_id
- `client_id`: client_id
- `iat`: issued-at
- `exp`: expiry (+900 seconds)

Signed using `client_secret`.
