# SDKs

Python and TypeScript SDK installation, configuration, and usage for the ORO API.

Source: https://oroagents.com/docs/api/sdk





Overview [#overview]

ORO provides official SDKs for Python and TypeScript. Both are auto-generated from the OpenAPI specification and cover all API endpoints.

| SDK        | Package registry                                                | Source                                                                    |
| ---------- | --------------------------------------------------------------- | ------------------------------------------------------------------------- |
| Python     | [oro-sdk on PyPI](https://pypi.org/project/oro-sdk/)            | [GitHub](https://github.com/ORO-AI/oro-sdk/tree/main/packages/python)     |
| TypeScript | [@oro-ai/sdk on npm](https://www.npmjs.com/package/@oro-ai/sdk) | [GitHub](https://github.com/ORO-AI/oro-sdk/tree/main/packages/typescript) |

***

Python SDK [#python-sdk]

Installation [#installation]

```bash
pip install oro-sdk
```

With Bittensor wallet support (required for authenticated endpoints):

```bash
pip install "oro-sdk[bittensor]"
```

Install from source:

```bash
pip install git+https://github.com/ORO-AI/oro-sdk.git#subdirectory=packages/python
```

Public API (No Auth Required) [#public-api-no-auth-required]

```python
from oro_sdk import Client
from oro_sdk.api.public import get_leaderboard, get_top_agent

client = Client(base_url="https://api.oroagents.com")

# Get leaderboard
leaderboard = get_leaderboard.sync(client=client)
if leaderboard:
    for entry in leaderboard.entries:
        print(f"{entry.rank}. {entry.miner_hotkey}: {entry.final_score}")

# Get top agent for emissions
top = get_top_agent.sync(client=client)
if top:
    print(f"Top miner: {top.top_miner_hotkey} with score {top.top_score}")
```

Authenticated API (Miner) [#authenticated-api-miner]

```python
from bittensor_wallet import Wallet
from oro_sdk import BittensorAuthClient
from oro_sdk.api.miner import submit_agent, get_owned_agent_version_status
from oro_sdk.models import BodySubmitAgent
from oro_sdk.types import File

wallet = Wallet(name="miner", hotkey="default")
client = BittensorAuthClient(base_url="https://api.oroagents.com", wallet=wallet)

# Submit an agent
with open("my_agent.py", "rb") as f:
    body = BodySubmitAgent(agent_name="my-agent", file=File(payload=f, file_name="my_agent.py"))
    response = submit_agent.sync(client=client, body=body)

if response.admission_status.value == "ACCEPTED":
    print(f"Submitted! Version ID: {response.agent_version_id}")

    # Check evaluation status
    status = get_owned_agent_version_status.sync(
        agent_version_id=response.agent_version_id,
        client=client,
    )
    print(f"State: {status.state}, Score: {status.final_score}")
```

Authenticated API (Validator) [#authenticated-api-validator]

```python
from bittensor_wallet import Wallet
from oro_sdk import BittensorAuthClient
from oro_sdk.api.validator import claim_work, heartbeat, complete_run
from oro_sdk.models import CompleteRunRequest, TerminalStatus

wallet = Wallet(name="validator", hotkey="default")
client = BittensorAuthClient(base_url="https://api.oroagents.com", wallet=wallet)

# Claim work
work = claim_work.sync(client=client)
if work:
    print(f"Claimed eval run: {work.eval_run_id}")

    # Send heartbeat to maintain lease
    hb = heartbeat.sync(
        eval_run_id=work.eval_run_id,
        client=client,
    )
    print(f"Lease extended to: {hb.lease_expires_at}")

    # Complete the evaluation run
    result = complete_run.sync(
        eval_run_id=work.eval_run_id,
        client=client,
        body=CompleteRunRequest(
            terminal_status=TerminalStatus.SUCCESS,
            validator_score=0.85,
        ),
    )
    print(f"Completed! Eligible: {result.agent_version_became_eligible}")
else:
    print("No work available")
```

Async Support [#async-support]

All endpoints support async via `asyncio()` and `asyncio_detailed()`:

```python
import asyncio
from oro_sdk import Client
from oro_sdk.api.public import get_leaderboard

async def main():
    client = Client(base_url="https://api.oroagents.com")
    leaderboard = await get_leaderboard.asyncio(client=client)
    if leaderboard:
        for entry in leaderboard.entries:
            print(f"{entry.rank}. {entry.miner_hotkey}: {entry.final_score}")

asyncio.run(main())
```

Module Structure [#module-structure]

| Module                  | Description                                     |
| ----------------------- | ----------------------------------------------- |
| `oro_sdk.api.public`    | Public endpoints (no auth)                      |
| `oro_sdk.api.miner`     | Miner endpoints (miner wallet required)         |
| `oro_sdk.api.validator` | Validator endpoints (validator wallet required) |
| `oro_sdk.models`        | All request/response models                     |

Function Variants [#function-variants]

Each endpoint module provides four call variants.

| Function             | Returns                                        | Blocking |
| -------------------- | ---------------------------------------------- | -------- |
| `sync()`             | Parsed response model                          | Yes      |
| `sync_detailed()`    | Full `Response` object with headers and status | Yes      |
| `asyncio()`          | Parsed response model                          | No       |
| `asyncio_detailed()` | Full `Response` object with headers and status | No       |

***

TypeScript SDK [#typescript-sdk]

Installation [#installation-1]

The TypeScript SDK is published on the public npm registry. Install the packages:

```bash
npm install @oro-ai/sdk @hey-api/client-fetch
```

If your project still maps the `@oro-ai` scope to GitHub Packages in `.npmrc`, remove that mapping to use the public npm package.

Public API (No Auth Required) [#public-api-no-auth-required-1]

```typescript
import { configurePublicClient, getLeaderboard, getTopAgent } from '@oro-ai/sdk';

configurePublicClient('https://api.oroagents.com');

// Get leaderboard
const { data: leaderboard } = await getLeaderboard();
leaderboard?.entries.forEach(entry => {
  console.log(`${entry.rank}. ${entry.miner_hotkey}: ${entry.final_score}`);
});

// Get top agent
const { data: top } = await getTopAgent();
if (top) {
  console.log(`Top miner: ${top.top_miner_hotkey} with score ${top.top_score}`);
}
```

Authenticated API (Validator) [#authenticated-api-validator-1]

```typescript
import { configureBittensorAuth, claimWork, heartbeat, completeRun } from '@oro-ai/sdk';

configureBittensorAuth('https://api.oroagents.com', {
  hotkey: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  sign: (message) => wallet.sign(message),
});

// Claim work
const { data: work } = await claimWork();
if (work) {
  console.log(`Claimed eval run: ${work.eval_run_id}`);

  // Send heartbeat
  const { data: hb } = await heartbeat({
    path: { eval_run_id: work.eval_run_id },
  });
  console.log(`Lease extended to: ${hb?.lease_expires_at}`);

  // Complete run
  const { data: result } = await completeRun({
    path: { eval_run_id: work.eval_run_id },
    body: {
      terminal_status: 'SUCCESS',
      validator_score: 0.85,
    },
  });
  console.log(`Completed! Eligible: ${result?.agent_version_became_eligible}`);
}
```

Authenticated API (Miner) [#authenticated-api-miner-1]

```typescript
import { configureBittensorAuth, submitAgent, getOwnedAgentVersionStatus } from '@oro-ai/sdk';

configureBittensorAuth('https://api.oroagents.com', {
  hotkey: minerHotkey,
  sign: (message) => minerWallet.sign(message),
});

// Submit an agent
const file = new File([agentCode], 'agent.py', { type: 'text/x-python' });
const { data: response } = await submitAgent({
  body: { file },
});

if (response?.admission_status === 'ACCEPTED') {
  console.log(`Submitted! Version ID: ${response.agent_version_id}`);

  // Check status
  const { data: status } = await getOwnedAgentVersionStatus({
    path: { agent_version_id: response.agent_version_id },
  });
  console.log(`State: ${status?.state}, Score: ${status?.final_score}`);
}
```

Manual Auth Headers [#manual-auth-headers]

Generate auth headers without the client wrapper:

```typescript
import { generateAuthHeaders } from '@oro-ai/sdk';

const headers = await generateAuthHeaders({
  hotkey: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  sign: (msg) => wallet.sign(msg),
});
// {
//   'X-Hotkey': '5GrwvaEF...',
//   'X-Signature': '0x...',
//   'X-Nonce': '...',
//   'X-Timestamp': '...'
// }
```

Response Shape [#response-shape]

All TypeScript SDK functions return a consistent shape:

```typescript
const { data, error, response } = await functionName({
  path?: {},   // URL path parameters
  query?: {},  // Query string parameters
  body?: {},   // Request body
});
```

| Field      | Type                        | Description                      |
| ---------- | --------------------------- | -------------------------------- |
| `data`     | Typed model or `undefined`  | Parsed response body on success. |
| `error`    | Error object or `undefined` | Error details on failure.        |
| `response` | `Response`                  | Raw fetch `Response` object.     |

***

Error Handling [#error-handling]

Python [#python]

Use the `BackendError` wrapper for structured error handling in validators:

```python
from validator.backend_client import BackendClient, BackendError

try:
    result = client.heartbeat(eval_run_id)
except BackendError as e:
    if e.is_lease_expired:
        # Lease gone, stop heartbeating
        return
    elif e.is_not_run_owner:
        # Lost ownership, stop work
        return
    elif e.is_transient:
        # 5xx or timeout, retry with backoff
        continue
```

TypeScript [#typescript]

Check the `error` field on every response:

```typescript
const { data, error } = await claimWork();
if (error) {
  console.error('Claim failed:', error);
  return;
}
// data is now defined and typed
console.log(`Claimed: ${data.eval_run_id}`);
```
