> ## Documentation Index
> Fetch the complete documentation index at: https://docs.altrina.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Models & Types

> Data models, types, and configurations in the Altrina SDK

## Overview

The Altrina SDK uses Pydantic models for data validation and type safety. All models are fully typed for better IDE support and runtime validation.

```python theme={null}
from altrina_sdk import (
    BrowserConfig,
    JobStatus,
    JobResult,
    JobStatusEnum,
    ActionSelectionModel
)
```

## BrowserConfig

Configuration options for browser sessions.

```python theme={null}
class BrowserConfig(BaseModel):
    width: int = 1920           # Viewport width (320-4096)
    height: int = 1080          # Viewport height (320-4096)
    residential_ip: bool = False  # Use residential IP proxy
    max_duration_minutes: int = 30  # Max duration (1-240)
    idle_timeout_minutes: int = 2   # Idle timeout (1-60)
    use_user_browser_profile: bool = False  # Use persistent user profile
```

### Fields

<ParamField path="width" type="integer" default="1920">
  Browser viewport width in pixels. Must be between 320 and 4096.
</ParamField>

<ParamField path="height" type="integer" default="1080">
  Browser viewport height in pixels. Must be between 320 and 4096.
</ParamField>

<ParamField path="residential_ip" type="boolean" default="False">
  Whether to use residential IP proxy for geo-restricted content or sites with anti-bot measures.
</ParamField>

<ParamField path="max_duration_minutes" type="integer" default="30">
  Maximum duration for the browser session in minutes. Must be between 1 and 240.
</ParamField>

<ParamField path="idle_timeout_minutes" type="integer" default="2">
  Time to wait before timing out an idle session. Must be between 1 and 60.
</ParamField>

<ParamField path="use_user_browser_profile" type="boolean" default="False">
  Use user's persistent browser profile (cookies, localStorage, etc.) instead of a fresh profile for each job. When False (default), each job starts with a clean browser profile.
</ParamField>

### Examples

```python theme={null}
from altrina_sdk import BrowserConfig

# Default configuration
config = BrowserConfig()

# Mobile viewport
mobile_config = BrowserConfig(
    width=375,
    height=812
)

# High-security configuration
secure_config = BrowserConfig(
    residential_ip=True,
    max_duration_minutes=60,
    idle_timeout_minutes=5
)

# Desktop 4K viewport
desktop_4k = BrowserConfig(
    width=3840,
    height=2160
)

# Persistent user profile (maintains cookies/localStorage across jobs)
persistent_profile = BrowserConfig(
    use_user_browser_profile=True
)

# Validation example
try:
    invalid_config = BrowserConfig(width=5000)  # Too large
except ValidationError as e:
    print(f"Invalid config: {e}")
```

## ActionSelectionModel

AI models available for browser action selection.

```python theme={null}
class ActionSelectionModel(str, Enum):
    CLAUDE_SONNET = "claude-sonnet-4-20250514"
    GEMINI_FLASH = "gemini/gemini-2.5-flash"
    GPT_4O = "gpt-4o"
```

### Available Models

| Model           | Value                        | Description                 | Best For                          |
| --------------- | ---------------------------- | --------------------------- | --------------------------------- |
| `CLAUDE_SONNET` | `"claude-sonnet-4-20250514"` | Claude 3.5 Sonnet (Default) | General automation, best accuracy |
| `GPT_4O`        | `"gpt-4o"`                   | OpenAI GPT-4                | Complex reasoning, creative tasks |
| `GEMINI_FLASH`  | `"gemini/gemini-2.5-flash"`  | Google Gemini Flash         | Fast, cost-effective tasks        |

### Usage

```python theme={null}
from altrina_sdk import BrowserAgent, ActionSelectionModel

# Using enum
agent = BrowserAgent(
    api_key="YOUR_API_KEY",
    model=ActionSelectionModel.CLAUDE_SONNET
)

# Using string value
agent = BrowserAgent(
    api_key="YOUR_API_KEY",
    model="gpt-4o"
)

# Get default model
default = ActionSelectionModel.default()
print(f"Default model: {default.value}")
```

## JobStatusEnum

Possible job status values.

```python theme={null}
class JobStatusEnum(str, Enum):
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    USER_TAKEN_OVER = "user_taken_over"
    PAUSED = "paused"
```

### Status Values

| Status            | Description                         | Final State |
| ----------------- | ----------------------------------- | ----------- |
| `RUNNING`         | Job is currently executing          | No          |
| `PAUSED`          | Job is paused and waiting to resume | No          |
| `COMPLETED`       | Job finished successfully           | Yes         |
| `FAILED`          | Job encountered an error            | Yes         |
| `USER_TAKEN_OVER` | User took manual control            | Yes         |

### Example

```python theme={null}
from altrina_sdk import JobStatusEnum

def is_job_done(status: JobStatusEnum) -> bool:
    """Check if job is in a final state."""
    return status in [
        JobStatusEnum.COMPLETED,
        JobStatusEnum.FAILED,
        JobStatusEnum.USER_TAKEN_OVER
    ]

# Usage
if status == JobStatusEnum.COMPLETED:
    print("Success!")
elif status == JobStatusEnum.FAILED:
    print("Job failed")
elif status == JobStatusEnum.PAUSED:
    print("Job is paused - resume to continue")
```

## JobStatus

Complete job status information.

```python theme={null}
class JobStatus(BaseModel):
    job_id: str                          # Unique job identifier
    user_id: str                         # Owner user ID
    directive: Optional[str]             # Original instruction
    status: JobStatusEnum                # Current status
    output: Optional[Dict[str, Any]]    # Result data
    error: Optional[str]                 # Error message if failed
    live_url: Optional[str]              # Live viewing URL
    cdp_url: Optional[str]               # Chrome DevTools URL
    history_url: Optional[str]           # History viewing URL
    credits_used: Optional[int]          # Credits consumed
    credit_balance: Optional[int]        # Remaining credits
    created_at: Optional[datetime]       # Creation timestamp
    updated_at: Optional[datetime]       # Last update timestamp
```

### Fields

<ParamField path="job_id" type="string" required>
  Unique identifier for the job.
</ParamField>

<ParamField path="user_id" type="string" required>
  ID of the user who owns this job.
</ParamField>

<ParamField path="directive" type="string">
  The original natural language instruction.
</ParamField>

<ParamField path="status" type="JobStatusEnum" required>
  Current job status.
</ParamField>

<ParamField path="output" type="dict">
  The extracted data or results when completed.
</ParamField>

<ParamField path="error" type="string">
  Error message if the job failed.
</ParamField>

<ParamField path="live_url" type="string">
  URL to watch the live browser session.
</ParamField>

<ParamField path="cdp_url" type="string">
  Chrome DevTools Protocol URL for debugging.
</ParamField>

<ParamField path="history_url" type="string">
  URL to view session history and logs.
</ParamField>

<ParamField path="credits_used" type="integer">
  Number of credits consumed by this job.
</ParamField>

<ParamField path="credit_balance" type="integer">
  User's remaining credit balance.
</ParamField>

<ParamField path="created_at" type="datetime">
  When the job was created.
</ParamField>

<ParamField path="updated_at" type="datetime">
  When the job was last updated.
</ParamField>

### Example

```python theme={null}
from altrina_sdk import AltrinaClient

client = AltrinaClient("YOUR_API_KEY")
status = client.get_job_status("job_abc123")

# Access fields
print(f"Job ID: {status.job_id}")
print(f"Status: {status.status}")
print(f"Credits used: {status.credits_used}")

if status.status == "completed":
    print(f"Output: {status.output}")
elif status.status == "failed":
    print(f"Error: {status.error}")

# Calculate duration
if status.created_at and status.updated_at:
    duration = (status.updated_at - status.created_at).total_seconds()
    print(f"Duration: {duration:.2f} seconds")
```

## JobResult

Final result of a completed job.

```python theme={null}
class JobResult(BaseModel):
    job_id: str                          # Job identifier
    status: JobStatusEnum                # Final status
    output: Optional[Dict[str, Any]]    # Result data
    error: Optional[str]                 # Error if failed
    credits_used: int                    # Credits consumed
    duration_seconds: Optional[float]    # Job duration
    
    @property
    def is_successful(self) -> bool:
        """Check if job completed successfully."""
        return self.status == JobStatusEnum.COMPLETED
    
    @property
    def is_failed(self) -> bool:
        """Check if job failed."""
        return self.status == JobStatusEnum.FAILED
    
    def get_output(self, key: Optional[str] = None) -> Any:
        """Get output data, optionally by key."""
        if not self.output:
            return None
        if key:
            return self.output.get(key)
        return self.output
```

### Properties and Methods

<ParamField path="is_successful" type="boolean">
  Returns `True` if the job completed successfully.
</ParamField>

<ParamField path="is_failed" type="boolean">
  Returns `True` if the job failed.
</ParamField>

<ParamField path="get_output(key)" type="method">
  Get output data, optionally by specific key.
</ParamField>

### Example

```python theme={null}
from altrina_sdk import BrowserAgent

agent = BrowserAgent("YOUR_API_KEY")
result = agent.run("Extract data from example.com")

# Check success
if result.is_successful:
    print(f"Success! Credits used: {result.credits_used}")
    
    # Access output
    data = result.output
    
    # Get specific field
    title = result.get_output("title")
    
    # Duration if available
    if result.duration_seconds:
        print(f"Took {result.duration_seconds:.2f} seconds")
else:
    print(f"Failed: {result.error}")
```

## Request/Response Models

### RunBrowserAgentRequest

Internal request model for starting browser agents.

```python theme={null}
class RunBrowserAgentRequest(BaseModel):
    directive: str                                  # Required instruction
    initial_url: Optional[str] = None              # Starting URL
    cdp_url: Optional[str] = None                  # Custom browser CDP URL
    live_url: Optional[str] = None                 # Custom live view URL
    action_selection_model: ActionSelectionModel   # AI model
    browser_config: Optional[BrowserConfig] = None # Browser settings
```

### RunBrowserAgentResponse

Response when starting a browser agent.

```python theme={null}
class RunBrowserAgentResponse(BaseModel):
    job_id: str                    # Job identifier
    status: JobStatusEnum          # Initial status
    live_url: Optional[str]        # Live viewing URL
    cdp_url: Optional[str]         # Chrome DevTools URL
    history_url: str               # History URL
    polling_url: str               # Status polling endpoint
```

## Type Hints and Validation

The SDK provides full type hints for better IDE support:

```python theme={null}
from typing import Optional, Dict, Any
from altrina_sdk import BrowserAgent, JobResult

def extract_with_retry(
    agent: BrowserAgent,
    url: str,
    max_retries: int = 3
) -> Optional[Dict[str, Any]]:
    """Extract data with retry logic."""
    
    for attempt in range(max_retries):
        result: JobResult = agent.extract(
            url=url,
            data_description="all text content"
        )
        
        if result.is_successful:
            return result.output
    
    return None

# IDE will provide autocomplete and type checking
agent = BrowserAgent("YOUR_API_KEY")
data = extract_with_retry(agent, "https://example.com")
```

## Custom Models

You can extend the SDK models for your use case:

```python theme={null}
from pydantic import BaseModel, Field
from altrina_sdk import JobResult
from typing import List, Optional

class ProductData(BaseModel):
    """Custom model for product data."""
    name: str
    price: float
    availability: bool
    url: str

class ScrapingResult(BaseModel):
    """Extended result model."""
    job_result: JobResult
    products: List[ProductData]
    scraped_at: datetime
    
    @classmethod
    def from_job_result(cls, result: JobResult):
        """Create from JobResult."""
        products = []
        if result.is_successful and result.output:
            for item in result.output.get("products", []):
                products.append(ProductData(**item))
        
        return cls(
            job_result=result,
            products=products,
            scraped_at=datetime.now()
        )

# Usage
result = agent.run("Extract product data")
scraping_result = ScrapingResult.from_job_result(result)

for product in scraping_result.products:
    print(f"{product.name}: ${product.price}")
```

## Validation Examples

The SDK validates all inputs automatically:

```python theme={null}
from altrina_sdk import BrowserConfig
from pydantic import ValidationError

# Invalid width (too large)
try:
    config = BrowserConfig(width=5000)
except ValidationError as e:
    print(f"Validation error: {e}")
    # width: ensure this value is less than or equal to 4096

# Invalid duration (too long)
try:
    config = BrowserConfig(max_duration_minutes=500)
except ValidationError as e:
    print(f"Validation error: {e}")
    # max_duration_minutes: ensure this value is less than or equal to 240

# Valid configuration
config = BrowserConfig(
    width=1920,
    height=1080,
    residential_ip=True,
    max_duration_minutes=60
)
print(f"Valid config: {config.model_dump()}")
```

## JSON Serialization

All models support JSON serialization:

```python theme={null}
import json
from altrina_sdk import BrowserConfig, JobResult

# Serialize to JSON
config = BrowserConfig(width=1920, height=1080)
json_str = config.model_dump_json()
print(json_str)
# {"width": 1920, "height": 1080, "residential_ip": false, ...}

# Deserialize from JSON
json_data = '{"width": 1366, "height": 768}'
config = BrowserConfig.model_validate_json(json_data)
print(config.width)  # 1366

# Save results to file
result = agent.run("Extract data")
with open("result.json", "w") as f:
    json.dump(result.model_dump(), f, indent=2, default=str)
```

## See Also

* [BrowserAgent](/sdk/browser-agent) - Using models with BrowserAgent
* [Error Handling](/sdk/error-handling) - Exception types and handling
* [API Reference](/api-reference/quickstart) - REST API models
