---
url: /sdk-api-platform.md
description: >-
  Catalog surface for the Kipu Quantum Hub - services, applications,
  organizations, data pools, subscriptions, marketplace listings, and billing
  through the HubPlatformClient.
---

# HubPlatformClient

> Part of the [Kipu Quantum Hub API SDK reference](./sdk-api.md) - see the landing page for [installation](./sdk-api.md#installation) and [Python credential helpers](./sdk-api.md#python-credential-helpers).

`HubPlatformClient` covers the catalog surface: services, applications, organizations, data pools, subscriptions, marketplace listings, billing, and more.
The constructor has the same shape as `HubQuantumClient`, including the `organization_id` / `organizationId` option.

## Authentication

`HubPlatformClient` authenticates with a personal access token sent as the `X-Auth-Token` request header.
The same Python credential helpers documented under [Python credential helpers](./sdk-api.md#python-credential-helpers) work here - pass the resolved token via `api_key`.

## Organization scoping

Most Platform endpoints accept an `X-OrganizationId` header to scope the request to a specific organization.
`HubPlatformClient` exposes a dedicated `organization_id` / `organizationId` constructor option that sends the header on every request; in TypeScript, individual sub-client methods also accept a per-request override.
Leave it unset to operate in your personal account.

## Quickstart

::: tabs key:pythonTS

\== Python

```python
from qhub.api.platform import HubPlatformClient

platform = HubPlatformClient(
    api_key="YOUR_PERSONAL_ACCESS_TOKEN",
    organization_id="YOUR_ORGANIZATION_ID",
)

services = platform.services.get_services(page=0, size=20)
for service in services.content or []:
    print(service.id, service.display_name)
```

\== TypeScript

```ts
import { HubPlatformClient } from "@quantum-hub/qhub-api/platform";

const platform = new HubPlatformClient({
  apiKey: process.env.KQH_PERSONAL_ACCESS_TOKEN!,
  organizationId: process.env.KQH_ORGANIZATION_ID!,
});

const services = await platform.services.getServices({ page: 0, size: 20 });
for (const service of services.content ?? []) {
  console.log(service.id, service.displayName);
}
```

:::

## Constructor

| Parameter                            | Required         | Description                                                                                      |
|--------------------------------------|------------------|--------------------------------------------------------------------------------------------------|
| `api_key` / `apiKey`                 | yes              | Personal access token; sent as `X-Auth-Token`.                                                   |
| `base_url` / `baseUrl`               | no               | Overrides both the default environment and `environment` if supplied.                            |
| `environment`                        | no               | `HubPlatformClientEnvironment.DEFAULT` (Python) / `HubPlatformEnvironment.Default` (TypeScript). |
| `organization_id` / `organizationId` | no               | Value for the `X-OrganizationId` header; sent on every request from this client.                 |
| `headers`                            | no               | Additional headers merged into every request.                                                    |
| `timeout` / `timeoutInSeconds`       | no               | Read timeout in seconds; defaults to 60 when no custom HTTP client is supplied.                  |
| `max_retries` / `maxRetries`         | no               | Number of retries for transient failures; defaults to 2.                                         |
| `follow_redirects`                   | no (Python only) | Passed through to `httpx.Client`; defaults to `True`.                                            |
| `httpx_client` / `fetch`             | no               | Inject a preconfigured HTTP client (Python) or `fetch` implementation (TypeScript).              |
| `logging`                            | no               | Logger instance or `{level, logger, silent}` config dict.                                        |

Python also ships `AsyncHubPlatformClient` with the same shape plus an `httpx.AsyncClient` hook.

## Namespaces

`HubPlatformClient` exposes the following sub-clients, lazily instantiated on first access.

| Namespace            | Purpose                                                                          |
|----------------------|----------------------------------------------------------------------------------|
| `algorithms`         | Algorithms in the catalog and their sketches, relations, and access permissions. |
| `applications`       | Applications (projects that consume services).                                   |
| `authentication`     | Access tokens and keys (API tokens, APIM / gateway credentials).                 |
| `billing`            | Balances, budgets, credits, billing history, revenue, cost reports.              |
| `data_pools`         | Data pools (shared datasets) and their files.                                    |
| `data_pool_grants`   | Grants that let services read from a data pool.                                  |
| `data_pool_shares`   | Visibility grants of data pools to users or organizations.                       |
| `eligibility`        | Entitlement and eligibility checks for the current principal.                    |
| `external_services`  | Externally-hosted services registered in the catalog.                            |
| `git_integrations`   | Git provider integrations used by services.                                      |
| `implementations`    | Implementations attached to algorithms.                                          |
| `managed_services`   | Managed services (Hub-hosted) including builds and source upload.                |
| `marketplace`        | Marketplace listings for algorithms, services, implementations, use cases.       |
| `organizations`      | Organizations you belong to, members, provider tokens.                           |
| `quantum_workloads`  | Cross-organization view of quantum workload costs (reporting surface).           |
| `service_executions` | Service execution records, inputs, outputs, logs, metrics, cancellation.         |
| `service_jobs`       | Service jobs (the subset of execution records that are long-running jobs).       |
| `service_shares`     | Visibility grants of services to users or organizations.                         |
| `services`           | Services in the catalog (the published, versioned artefacts).                    |
| `subscriptions`      | Subscriptions (for services that require opt-in).                                |
| `use_cases`          | Use cases exposed in the catalog / marketplace.                                  |
| `user_notifications` | Per-user notifications.                                                          |
| `users`              | Invitations, accounts, and per-user provider tokens.                             |
| `workflow_services`  | Workflow services (multi-step managed services).                                 |

User-profile data (name, email, profile image, personal access tokens) now lives on `HubUserClient` - see [HubUserClient](./sdk-api-user.md).

## Endpoints

| Default base URL                              | Override                                                                                                                              |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `https://api.hub.kipu-quantum.com/qc-catalog` | `base_url=...` / `baseUrl: ...`, or `environment=HubPlatformClientEnvironment.DEFAULT` (Python) / `environment: HubPlatformEnvironment.Default` (TypeScript). |

## Errors

All Python errors extend `ApiError` (in `qhub.api.platform.core.api_error`); all TypeScript errors extend `HubPlatformError`.

| Status | Python class                  | TypeScript class              | Meaning                                              |
| ------ | ----------------------------- | ----------------------------- | ---------------------------------------------------- |
| 400    | `BadRequestError`             | `BadRequestError`             | Malformed request.                                   |
| 401    | `UnauthorizedError`           | `UnauthorizedError`           | Missing or invalid credentials.                      |
| 403    | `ForbiddenError`              | `ForbiddenError`              | Authenticated but not permitted.                     |
| 404    | `NotFoundError`               | `NotFoundError`               | Resource does not exist.                             |
| 409    | `ConflictError`               | `ConflictError`               | Conflict with current state, e.g. publication races. |
| 413    | `ContentTooLargeError`        | `ContentTooLargeError`        | Upload exceeds the configured size limit.            |
| 415    | `UnsupportedMediaTypeError`   | `UnsupportedMediaTypeError`   | Wrong `Content-Type` on the request body.            |
| 422    | `UnprocessableEntityError`    | `UnprocessableEntityError`    | Validation failure on the request body.              |
| 500    | `InternalServerError`         | `InternalServerError`         | Server-side failure.                                 |

Other failure modes:

* **Auth misconfiguration (TypeScript)** - constructing `HubPlatformClient` without `apiKey` throws `HubPlatformError` with message `"Please provide 'apiKey' when initializing the client"`.
* **Timeouts** - hitting `timeoutInSeconds` raises `HubPlatformTimeoutError` in TypeScript; in Python, timeouts surface as the underlying `httpx.TimeoutException`.

All HTTP error instances expose `status_code`, `headers`, and `body` (Python) / `statusCode`, `rawResponse`, and `body` (TypeScript).

## Reference

### Field casing

Platform-API DTOs use snake\_case in Python (`created_at`, `display_name`) and camelCase in TypeScript (`createdAt`, `displayName`).

### Pagination wrappers

Identical to the Quantum API - `{content, page, size, total_elements, total_pages}`, zero-based `page`.
