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

# Client Libraries

> Official SDKs for Python, Node.js, and .NET — with auto-pagination, retries, and full type safety out of the box.

Jobo Enterprise provides official client libraries for three languages. Each SDK wraps the REST API with idiomatic helpers so you can skip boilerplate and focus on building.

<CardGroup cols={3}>
  <Card title="Python" icon="python" href="#python">
    Python 3.9+ · Pydantic models · sync + async
  </Card>

  <Card title="Node.js" icon="node-js" href="#nodejs--typescript">
    Node 18+ · TypeScript 5+ · zero dependencies
  </Card>

  <Card title=".NET" icon="microsoft" href="#net">
    .NET 6+ / 8+ · IAsyncEnumerable · DI-ready
  </Card>
</CardGroup>

***

## Feature Comparison

All three SDKs share a common feature set:

| Feature                         |      Python      |    Node.js / TS   |         .NET         |
| ------------------------------- | :--------------: | :---------------: | :------------------: |
| Jobs Search                     |         ✅        |         ✅         |           ✅          |
| Advanced Query (AND/OR filters) |         ✅        |         ✅         |           ✅          |
| Jobs Feed (cursor-based)        |         ✅        |         ✅         |           ✅          |
| Expired Jobs                    |         ✅        |         ✅         |           ✅          |
| Auto Apply                      |         ✅        |         ✅         |           ✅          |
| Geocode                         |         ✅        |         ✅         |           ✅          |
| Auto-pagination                 | ✅ typed iterator | ✅ async generator | ✅ `IAsyncEnumerable` |
| Retry with exponential backoff  |         ✅        |         ✅         |           ✅          |
| Full type definitions           |    ✅ Pydantic    |    ✅ TypeScript   |     ✅ C# records     |
| Async support                   |  ✅ sync + async  |   ✅ native async  |    ✅ native async    |

***

## Python

### Requirements

* **Python 3.9+**
* Dependencies: `httpx`, `pydantic`

### Installation

```bash theme={null}
pip install jobo-enterprise
```

### Quick Example

```python theme={null}
from jobo_enterprise import JoboClient

client = JoboClient(api_key="YOUR_API_KEY")

# Search for remote data-science jobs in the US
results = client.jobs.search(
    q="data scientist",
    location="United States",
    is_remote=True,
    page_size=10
)

print(f"Found {results.total} jobs")
for job in results.jobs:
    print(f"  {job.title} at {job.company.name} — {job.source}")
```

### Advanced Usage

<AccordionGroup>
  <Accordion title="Auto-Pagination">
    Iterate over all matching jobs without managing page numbers. The SDK fetches
    the next page automatically when the current one is exhausted.

    ```python theme={null}
    for job in client.jobs.search_iter(q="machine learning engineer"):
        print(job.title, job.company.name)
    ```

    The async variant works identically:

    ```python theme={null}
    async for job in client.jobs.async_search_iter(q="machine learning engineer"):
        print(job.title, job.company.name)
    ```
  </Accordion>

  <Accordion title="Error Handling">
    The SDK raises typed exceptions so you can handle specific failure modes.

    ```python theme={null}
    from jobo_enterprise.exceptions import (
        JoboAuthError,
        JoboRateLimitError,
        JoboApiError,
    )

    try:
        results = client.jobs.search(q="engineer")
    except JoboAuthError:
        print("Invalid API key — check your credentials")
    except JoboRateLimitError as e:
        print(f"Rate limited — retry after {e.retry_after}s")
    except JoboApiError as e:
        print(f"API error {e.status}: {e.message}")
    ```
  </Accordion>

  <Accordion title="Async Client">
    Use `AsyncJoboClient` for non-blocking I/O in async frameworks like
    FastAPI or Django Channels.

    ```python theme={null}
    from jobo_enterprise import AsyncJoboClient

    client = AsyncJoboClient(api_key="YOUR_API_KEY")

    results = await client.jobs.search(q="backend engineer", page_size=25)
    for job in results.jobs:
        print(job.title)
    ```
  </Accordion>
</AccordionGroup>

### Features

* **Pydantic models** — every response is a fully-typed Pydantic model with IDE autocompletion
* **Sync + async** — choose `JoboClient` (sync/httpx) or `AsyncJoboClient` (async/httpx)
* **Typed iterator pagination** — `search_iter()` / `async_search_iter()` lazily page through all results
* **Automatic retries** — transient errors (429, 500, 502, 503, 504) are retried with exponential backoff

### Links

<CardGroup cols={2}>
  <Card title="PyPI" icon="box" href="https://pypi.org/project/jobo-enterprise/">
    pypi.org/project/jobo-enterprise
  </Card>

  <Card title="GitHub" icon="github" href="https://github.com/Prakkie91/jobo-python">
    github.com/Prakkie91/jobo-python
  </Card>
</CardGroup>

***

## Node.js / TypeScript

### Requirements

* **Node.js 18+**
* **TypeScript 5+** (optional but recommended)
* Zero runtime dependencies

### Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install jobo-enterprise
  ```

  ```bash yarn theme={null}
  yarn add jobo-enterprise
  ```

  ```bash pnpm theme={null}
  pnpm add jobo-enterprise
  ```
</CodeGroup>

### Quick Example

```typescript theme={null}
import { JoboClient } from "jobo-enterprise";

const client = new JoboClient({ apiKey: "YOUR_API_KEY" });

// Search for remote frontend jobs
const results = await client.jobs.search({
  q: "frontend engineer",
  isRemote: true,
  pageSize: 10,
});

console.log(`Found ${results.total} jobs`);
results.jobs.forEach((job) => {
  console.log(`  ${job.title} at ${job.company.name} — ${job.source}`);
});
```

### Advanced Usage

<AccordionGroup>
  <Accordion title="Auto-Pagination with Async Generators">
    Use `searchIter()` to stream through every page of results automatically.

    ```typescript theme={null}
    for await (const job of client.jobs.searchIter({ q: 'devops' })) {
      console.log(job.title, job.company.name);
    }
    ```

    You can also collect all results into an array:

    ```typescript theme={null}
    const allJobs = [];
    for await (const job of client.jobs.searchIter({ q: 'devops' })) {
      allJobs.push(job);
    }
    console.log(`Collected ${allJobs.length} jobs`);
    ```
  </Accordion>

  <Accordion title="Error Handling">
    Catch typed error classes for granular control.

    ```typescript theme={null}
    import { JoboAuthError, JoboRateLimitError, JoboApiError } from 'jobo-enterprise';

    try {
      const results = await client.jobs.search({ q: 'engineer' });
    } catch (err) {
      if (err instanceof JoboAuthError) {
        console.error('Invalid API key');
      } else if (err instanceof JoboRateLimitError) {
        console.error(`Rate limited — retry after ${err.retryAfter}s`);
      } else if (err instanceof JoboApiError) {
        console.error(`API error ${err.status}: ${err.message}`);
      }
    }
    ```
  </Accordion>

  <Accordion title="Custom Fetch / Proxy">
    Pass a custom `fetch` implementation for proxies, logging, or test mocking.

    ```typescript theme={null}
    import { JoboClient } from 'jobo-enterprise';

    const client = new JoboClient({
      apiKey: 'YOUR_API_KEY',
      fetch: myCustomFetch,        // drop-in fetch replacement
      baseUrl: 'https://proxy.internal/jobo',  // optional base URL override
    });
    ```
  </Accordion>
</AccordionGroup>

### Features

* **Zero dependencies** — uses the built-in `fetch` API (Node 18+)
* **Full TypeScript types** — every request and response is strongly typed
* **Async generator pagination** — `searchIter()` yields jobs across pages with `for await...of`
* **Automatic retries** — transient errors are retried with exponential backoff and jitter

### Links

<CardGroup cols={2}>
  <Card title="npm" icon="npm" href="https://www.npmjs.com/package/jobo-enterprise">
    npmjs.com/package/jobo-enterprise
  </Card>

  <Card title="GitHub" icon="github" href="https://github.com/Prakkie91/jobo-node">
    github.com/Prakkie91/jobo-node
  </Card>
</CardGroup>

***

## .NET

### Requirements

* **.NET 6.0+** or **.NET 8.0+**
* No additional dependencies beyond `System.Net.Http`

### Installation

```bash theme={null}
dotnet add package Jobo.Enterprise.Client
```

Or via the NuGet Package Manager:

```powershell theme={null}
Install-Package Jobo.Enterprise.Client
```

### Quick Example

```csharp theme={null}
using Jobo.Enterprise.Client;

var client = new JoboClient("YOUR_API_KEY");

// Search for backend jobs in London
var results = await client.Jobs.SearchAsync(new SearchRequest
{
    Q = "backend engineer",
    Location = "London",
    PageSize = 10
});

Console.WriteLine($"Found {results.Total} jobs");
foreach (var job in results.Jobs)
{
    Console.WriteLine($"  {job.Title} at {job.Company.Name} — {job.Source}");
}
```

### Advanced Usage

<AccordionGroup>
  <Accordion title="Auto-Pagination with IAsyncEnumerable">
    Stream through every page of results using C#'s native `await foreach`.

    ```csharp theme={null}
    await foreach (var job in client.Jobs.SearchEnumerableAsync(new SearchRequest
    {
        Q = "software engineer",
        IsRemote = true
    }))
    {
        Console.WriteLine($"{job.Title} at {job.Company.Name}");
    }
    ```

    This is memory-efficient — only one page is loaded at a time.
  </Accordion>

  <Accordion title="ASP.NET Core Dependency Injection">
    Register the client in your `IServiceCollection` for constructor injection.

    ```csharp theme={null}
    // Program.cs or Startup.cs
    builder.Services.AddJoboClient(options =>
    {
        options.ApiKey = builder.Configuration["Jobo:ApiKey"];
    });
    ```

    Then inject it into your controllers or services:

    ```csharp theme={null}
    public class JobsController : ControllerBase
    {
        private readonly IJoboClient _jobo;

        public JobsController(IJoboClient jobo)
        {
            _jobo = jobo;
        }

        [HttpGet("search")]
        public async Task<IActionResult> Search([FromQuery] string q)
        {
            var results = await _jobo.Jobs.SearchAsync(new SearchRequest { Q = q });
            return Ok(results);
        }
    }
    ```
  </Accordion>

  <Accordion title="Error Handling">
    Catch typed exceptions for precise error handling.

    ```csharp theme={null}
    using Jobo.Enterprise.Client.Exceptions;

    try
    {
        var results = await client.Jobs.SearchAsync(new SearchRequest { Q = "engineer" });
    }
    catch (JoboAuthException)
    {
        Console.WriteLine("Invalid API key");
    }
    catch (JoboRateLimitException ex)
    {
        Console.WriteLine($"Rate limited — retry after {ex.RetryAfter}s");
    }
    catch (JoboApiException ex)
    {
        Console.WriteLine($"API error {ex.StatusCode}: {ex.Message}");
    }
    ```
  </Accordion>
</AccordionGroup>

### Features

* **IAsyncEnumerable pagination** — `SearchEnumerableAsync` streams pages lazily with `await foreach`
* **ASP.NET Core DI** — first-class `AddJoboClient()` extension for dependency injection
* **C# records & nullable annotations** — every model is a record with full nullability annotations
* **Automatic retries** — configurable retry policy with exponential backoff for transient HTTP errors

### Links

<CardGroup cols={2}>
  <Card title="NuGet" icon="box" href="https://www.nuget.org/packages/Jobo.Enterprise.Client">
    nuget.org/packages/Jobo.Enterprise.Client
  </Card>

  <Card title="GitHub" icon="github" href="https://github.com/Prakkie91/jobo-dotnet">
    github.com/Prakkie91/jobo-dotnet
  </Card>
</CardGroup>

***

## Shared Capabilities

<Info>
  All three SDKs share the same design principles and feature guarantees.
</Info>

<CardGroup cols={3}>
  <Card title="Auto-Pagination" icon="arrow-right">
    Iterate through all results without manual page management. Each SDK uses
    its language's native streaming primitive.
  </Card>

  <Card title="Retry & Backoff" icon="rotate-right">
    Transient errors (429, 5xx) are automatically retried with exponential
    backoff and jitter. Configurable max retries.
  </Card>

  <Card title="Type Safety" icon="shield-check">
    Every request parameter and response field is fully typed — Pydantic models
    (Python), TypeScript interfaces (Node), C# records (.NET).
  </Card>
</CardGroup>

***

## REST API (No SDK)

Don't see your language? The REST API works with any HTTP client. Authenticate with the `X-Api-Key` header:

```bash theme={null}
curl "https://connect.jobo.world/api/jobs?q=designer&page_size=10" \
  -H "X-Api-Key: YOUR_API_KEY"
```

See the [Authentication](/authentication) page for details and the [API Reference](/api-reference/overview) for all available endpoints.

<Tip>
  Want an SDK for another language? [Open an
  issue](https://github.com/jobo-enterprise) on GitHub and we'll consider it for
  the roadmap.
</Tip>
