edupaid 1.1.0
A python package for interfacing with the Edupaid API
Requires Python: >=3.10

# Edupaid

A Python client for the Edupaid API.

## Installation

```bash
pip install edupaid
```

## Quick Start

```python
from edupaid import Edupaid

# Initialize the client (uses environment variables)
client = Edupaid()

# Or pass credentials directly
client = Edupaid(
    api_key="your-api-key",
    provider_id="your-provider-id",
    jwt_secret="your-jwt-secret",
)

# Access API methods via the service
# result = client.service.get_app_authorization(...)
```

## Configuration

### Environment Variables

The client reads configuration from environment variables. Add these to your `.env` file or set them in your environment:

| Variable | Required | Description |
|----------|----------|-------------|
| `EDUPAID_API_KEY` | Yes | API key for authentication (sent as `x-api-key` header) |
| `EDUPAID_PROVIDER_ID` | Yes | Your provider identifier |
| `EDUPAID_JWT_SECRET` | Yes | Secret for JWT/webhook signature verification |
| `EDUPAID_ENVIRONMENT` | No | `production` (default) or `staging` |

### Example `.env` file

```env
EDUPAID_API_KEY=your-api-key-here
EDUPAID_PROVIDER_ID=your-provider-id-here
EDUPAID_JWT_SECRET=your-jwt-secret-here
```

### Django Integration

For Django projects, ensure your environment variables are loaded before using the client:

```python
# settings.py
import environ

env = environ.Env()
environ.Env.read_env()  # Loads .env file

# In your views/services
from edupaid import Edupaid

client = Edupaid()  # Env vars are already loaded
```

## Error Handling

The client raises typed exceptions for different error scenarios:

```python
from edupaid import Edupaid
from edupaid.errors import (
    ConfigurationError,  # Missing/invalid configuration
    AuthError,           # 401 Unauthorized
    ValidationError,     # 400 Bad Request
    NotFoundError,       # 404 Not Found
    RateLimitError,      # 429 Too Many Requests
    ServerError,         # 5xx Server Errors
    RequestError,        # Other HTTP errors
)

try:
    client = Edupaid()
    # result = client.service.some_method(...)
except ConfigurationError as e:
    print(f"Configuration issue: {e}")
except AuthError as e:
    print(f"Authentication failed: {e}")
except NotFoundError as e:
    print(f"Resource not found: {e}")
except ValidationError as e:
    print(f"Invalid request: {e}")
```

All API errors include the error message from the API response:

```python
try:
    # ...
except NotFoundError as e:
    # Access the raw error dict from the API
    if e.error_details:
        api_message = e.error_details.get("error")
```

## API Reference

All endpoints are available via `client.service`. Full documentation for each endpoint is in `edupaid/docs/endpoints/`.

### get_app_authorization

Get learning track authorization status for a single student/track.

```python
from edupaid.models.request import EdupaidGetLearningTrackAuthorizationRequest
from edupaid.models.response import EdupaidLearningTrackAuthorizationResponse

request = EdupaidGetLearningTrackAuthorizationRequest(
    studentId="student-123",
    learningTrackId="track-456",
)
result: EdupaidLearningTrackAuthorizationResponse = client.service.get_app_authorization(request)
print(result.status)  # "unlocked", "locked", "scheduled", or "defaulted"
```

### list_app_authorizations

List all track authorizations for a student, categorized by status.

```python
from edupaid.models.request import EdupaidListLearningTrackAuthorizationsRequest
from edupaid.models.response import EdupaidListLearningTrackAuthorizationsResponse

request = EdupaidListLearningTrackAuthorizationsRequest(
    timebackStudentId="student-123",
    providerId=client.service.provider_id,  # optional
)
result: EdupaidListLearningTrackAuthorizationsResponse = client.service.list_app_authorizations(request)
print(f"Unlocked: {len(result.unlockedTracks)}, Locked: {len(result.lockedTracks)}")
```

### batch_get_app_authorization

Get authorization status for multiple students on a single track.

```python
from edupaid.models.request import EdupaidBatchGetLearningTrackAuthorizationRequest
from edupaid.models.response import EdupaidBatchGetLearningTrackAuthorizationResponse

request = EdupaidBatchGetLearningTrackAuthorizationRequest(
    learningTrackId="track-456",
    studentIds=["student-1", "student-2", "student-3"],
)
result: EdupaidBatchGetLearningTrackAuthorizationResponse = client.service.batch_get_app_authorization(request)
for r in result.results:
    print(f"{r.studentId}: {r.status}")
```

### submit_token

Submit a learning token (Mastery or TwoX) for a student.

```python
from edupaid.models.request import EdupaidSubmitTokenRequest
from edupaid.models.response import EdupaidSubmitTokenResponse
from edupaid.enums import EdupaidTokenType

request = EdupaidSubmitTokenRequest(
    studentId="student-123",
    timeBackAppId="app-456",
    type=EdupaidTokenType.MASTERY,
    data='{"curriculumId":"cur-1","score":95}',
    evidenceId="ev-789",
)
result: EdupaidSubmitTokenResponse = client.service.submit_token(request)
print(f"Token ID: {result.id}")
```

### generate_parent_token

Generate a time-limited URL for parent portal access.

```python
from edupaid.models.request import EdupaidGenerateParentTokenRequest
from edupaid.models.response import EdupaidGenerateParentTokenResponse

request = EdupaidGenerateParentTokenRequest(
    parentTimebackId="parent-123",
    expiryMinutes=60,  # optional, defaults to 60
)
result: EdupaidGenerateParentTokenResponse = client.service.generate_parent_token(request)
print(f"Portal URL: {result.url}")
```

### Endpoint Summary

| Method | Request Type | Response Type |
|--------|--------------|---------------|
| `get_app_authorization()` | `EdupaidGetLearningTrackAuthorizationRequest` | `EdupaidLearningTrackAuthorizationResponse` |
| `list_app_authorizations()` | `EdupaidListLearningTrackAuthorizationsRequest` | `EdupaidListLearningTrackAuthorizationsResponse` |
| `batch_get_app_authorization()` | `EdupaidBatchGetLearningTrackAuthorizationRequest` | `EdupaidBatchGetLearningTrackAuthorizationResponse` |
| `submit_token()` | `EdupaidSubmitTokenRequest` | `EdupaidSubmitTokenResponse` |
| `generate_parent_token()` | `EdupaidGenerateParentTokenRequest` | `EdupaidGenerateParentTokenResponse` |

## Requirements

- Python >= 3.10
- httpx
- pydantic >= 2.0

## License

MIT