# Trouver et provisionner des hubs

> Listez des hubs, lisez-en un, créez-en un, modifiez-le et suivez l'opération qui en découle.

Source: https://docs.thalovant.com/fr/developers/sdk-functions/finding-hubs/

---
{/* Last Edit: Claude Opus 5.5 - 2026-09-28 - Motive: Canadian French translation of developers/sdk-functions/finding-hubs.mdx. */}

Fait partie de [Fonctions des SDK](/fr/developers/sdk-functions/). Chaque appel ci-dessous est montré dans chaque langage qui l'offre.

## Désigner un hub par son nom

Un hub a un identifiant court (slug), un nom et parfois un titre de catalogue. Montrer le slug à une personne, c'est lui montrer la tuyauterie. Chaque SDK offre donc une fonction qui choisit le meilleur des trois et se rabat sur une forme lisible du slug.

  

```python
from thalovant.hubs import hub_display_name

hub_display_name({"slug": "kitchen-hub"})                      # "Kitchen Hub"
hub_display_name({"slug": "kitchen-hub", "name": "Kitchen"})   # "Kitchen"
hub_display_name({})                                           # "A Thalovant hub"
```

  
  

```ts

hubDisplayName({ slug: "kitchen-hub" }); // "Kitchen Hub"
```

  
  

```go
thalovant.HubDisplayName(map[string]any{"slug": "kitchen-hub"}) // "Kitchen Hub"
```

  
  

```rust
thalovant::hubs::hub_display_name(&hub) // "Kitchen Hub"
```

  
  

```kotlin
hubDisplayName(hub) // "Kitchen Hub"
```

  
  

```swift
hubDisplayName(hub) // "Kitchen Hub"
```

  
  

```csharp
Hubs.DisplayName(hub); // "Kitchen Hub"
```

  

L'ordre est le suivant : titre de catalogue, puis nom, puis slug. Un `name` identique au slug est traité comme le slug, parce qu'il n'apporte rien de plus. Si aucun des trois n'existe, la réponse est `A Thalovant hub` plutôt qu'un libellé vide.

## Lister les hubs publics

Utilisez la découverte des hubs publics avant de demander à une personne de choisir un hub.

  

```python
page = api.list_public_hubs(limit=12)

for hub in page["data"]:
    print(hub["id"], hub["slug"], hub["title"])
```

  
  

```ts
const page = await api.listPublicHubs({ limit: 12 });

for (const hub of page.data) {
  console.log(hub.id, hub.slug, hub.title);
}
```

  
  

```go
page, err := api.ListPublicHubs(ctx, 12, "")
if err != nil {
	log.Fatal(err)
}

for _, hub := range page.Data {
	fmt.Println(hub.ID, hub.Slug, hub.Title)
}
```

  
  

```rust
let page = api.list_public_hubs(Some(12), None).await?;

for hub in page.data {
    println!("{} {} {}", hub.id, hub.slug, hub.title);
}
```

  

## Obtenir un hub public

Utilisez cet appel quand vous avez une référence de hub tirée d'une URL, d'une carte ou d'un choix enregistré.

  

```python
hub = api.get_public_hub("joke-garden")
print(hub["title"], hub["public_ref"])
```

  
  

```ts
const hub = await api.getPublicHub("joke-garden");
console.log(hub.title, hub.publicRef);
```

  
  

```go
hub, err := api.GetPublicHub(ctx, "joke-garden")
if err != nil {
	log.Fatal(err)
}
fmt.Println(hub.Title, hub.PublicRef)
```

  
  

```rust
let hub = api.get_public_hub("joke-garden").await?;
println!("{} {}", hub.title, hub.public_ref);
```

  

## Lister les hubs visibles

Utilisez cet appel pour les hubs que l'espace de travail connecté peut voir.

  

```python
page = api.list_hubs(limit=25)

for hub in page["data"]:
    print(hub["id"], hub["title"])
```

  
  

```ts
const page = await api.listHubs({ limit: 25 });

for (const hub of page.data) {
  console.log(hub.id, hub.title);
}
```

  
  

```go
page, err := api.ListHubs(ctx, 25, "", "")
if err != nil {
	log.Fatal(err)
}

for _, hub := range page.Data {
	fmt.Println(hub.ID, hub.Title)
}
```

  
  

```rust
let page = api.list_hubs(Some(25), None, None).await?;

for hub in page.data {
    println!("{} {}", hub.id, hub.title);
}
```

  

## Obtenir un hub

Utilisez cet appel quand vous connaissez déjà l'ID du hub.

  

```python
hub = api.get_hub("hub-id")
print(hub["title"])
```

  
  

```ts
const hub = await api.getHub("hub-id");
console.log(hub.title);
```

  
  

```go
hub, err := api.GetHub(ctx, "hub-id")
if err != nil {
	log.Fatal(err)
}
fmt.Println(hub.Title)
```

  
  

```rust
let hub = api.get_hub("hub-id").await?;
println!("{}", hub.title);
```

  

## Provisionner un hub

Utilisez ces appels quand votre code doit créer le hub. La découverte exige `hubs:read` et fonctionne avec tous les forfaits. Les quatre écritures exigent `hubs:write` et un forfait payant. Pour la règle des etags, les champs non modifiables et le tableau des erreurs, consultez [Provisionner des hubs](/fr/developers/provisioning/).

  

```python
skills = api.list_marketplace_skills()["data"]

group = api.create_runtime_group({"name": "kiosks"})
hub = api.create_hub({
    "name": "joke-garden",
    "runtime_group_id": group["id"],
    "spec": {"protocols": {"wss": {"enabled": True}}},
})

api.install_runtime_group_skill(group["id"], "skill-weather")
api.release_runtime_group(group["id"], channel="stable")
api.release_hub(hub["id"], channel="stable")
```

  
  

```ts
const catalog = await api.listMarketplaceSkills();

const group = await api.createRuntimeGroup({ name: "kiosks" });
const hub = await api.createHub({
  name: "joke-garden",
  runtimeGroupId: group.id as string,
  spec: { protocols: { wss: { enabled: true } } },
});

await api.installRuntimeGroupSkill(group.id as string, "skill-weather");
await api.releaseRuntimeGroup(group.id as string, { channel: "stable" });
await api.releaseHub(hub.id as string, { channel: "stable" });
```

  
  

```go
catalog, err := api.ListMarketplaceSkills(ctx, thalovant.MarketplaceSkillListOptions{})

group, err := api.CreateRuntimeGroup(ctx, map[string]any{"name": "kiosks"})
groupID := group["id"].(string)

hub, err := api.CreateHub(ctx, map[string]any{
	"name":             "joke-garden",
	"runtime_group_id": groupID,
	"spec":             map[string]any{"protocols": map[string]any{"wss": map[string]any{"enabled": true}}},
}, thalovant.HubCreateOptions{})
hubID := hub["id"].(string)

_, err = api.InstallRuntimeGroupSkill(ctx, groupID, "skill-weather", thalovant.RuntimeGroupSkillInstallOptions{})
_, err = api.ReleaseRuntimeGroup(ctx, groupID, thalovant.ReleaseOptions{Channel: "stable"})
_, err = api.ReleaseHub(ctx, hubID, thalovant.ReleaseOptions{Channel: "stable"})
```

  
  

```rust
let catalog = api.list_marketplace_skills(MarketplaceSkillsOptions::default()).await?;

let group = api.create_runtime_group(json!({"name": "kiosks"})).await?;
let group_id = group["id"].as_str().unwrap_or_default().to_string();

let hub = api
    .create_hub(
        json!({
            "name": "joke-garden",
            "runtime_group_id": group_id,
            "spec": {"protocols": {"wss": {"enabled": true}}},
        }),
        None,
    )
    .await?;
let hub_id = hub["id"].as_str().unwrap_or_default().to_string();

api.install_runtime_group_skill(&group_id, "skill-weather", SkillInstallOptions::default()).await?;
api.release_runtime_group(&group_id, ReleaseOptions { channel: Some("stable".into()), ..Default::default() }).await?;
api.release_hub(&hub_id, ReleaseOptions { channel: Some("stable".into()), ..Default::default() }).await?;
```

  

Kotlin, Swift et .NET offrent les mêmes appels sous des noms propres à chaque langage. Leurs pages de SDK en montrent la forme.

## Modifier un hub avec son etag

La modification et la suppression d'un hub exigent l'etag actuel du hub, envoyé dans `If-Match`. Lisez d'abord le hub : l'etag est un champ du corps de la réponse, et l'API n'envoie aucun en-tête de réponse `ETag`.

  

```python
hub = api.get_hub("hub-id")
hub = api.update_hub("hub-id", {"active": False}, etag=hub["etag"])
api.delete_hub("hub-id", etag=hub["etag"])
```

  
  

```ts
let hub = await api.getHub("hub-id");
hub = await api.updateHub("hub-id", { active: false }, { etag: hub.etag as string });
await api.deleteHub("hub-id", { etag: hub.etag as string });
```

  
  

```go
hub, err := api.GetHub(ctx, "hub-id")
hub, err = api.UpdateHub(ctx, "hub-id", map[string]any{"active": false}, hub["etag"].(string))
err = api.DeleteHub(ctx, "hub-id", hub["etag"].(string))
```

  
  

```rust
let hub = api.get_hub("hub-id").await?;
let etag = hub["etag"].as_str().unwrap_or_default().to_string();

let hub = api.update_hub("hub-id", json!({"active": false}), &etag).await?;
let etag = hub["etag"].as_str().unwrap_or_default().to_string();
api.delete_hub("hub-id", &etag).await?;
```

  

Un etag manquant ou périmé échoue avec un HTTP 412 et ne change rien. Relisez le hub et réessayez.

## Interroger une opération acceptée

Utilisez l'ID d'opération renvoyé par une commande asynchrone du plan de contrôle. Arrêtez-vous à `ready`, `failed` ou `timed_out`; les commandes qui touchent seulement Git s'arrêtent à `committed`.

  

```python
operation = api.get_operation("operation-id")
print(operation.status)
```

  
  

```ts
const operation = await api.getOperation("operation-id");
console.log(operation.status);
```

  
  

```go
operation, err := api.GetOperation(ctx, "operation-id")
```

  
  

```rust
let operation = api.get_operation("operation-id").await?;
```

  

Consultez [Opérations](/fr/developers/operations/) pour le cycle de vie et les conseils sur les nouvelles tentatives.

## Gérer les compétences d'un hub

Utilisez ces appels pour gérer les compétences rattachées au groupe de runtime choisi par un hub. Chaque hub qui partage ce groupe de runtime est touché. Chaque écriture renvoie une opération; par défaut, `wait` l'interroge toutes les 2 secondes pendant au plus 120 secondes. Les écritures exigent `hubs:write` et un forfait payant; la liste exige `hubs:inspect`, qui est compris dans `hubs:read`. Les erreurs sont du JSON de type « problem » avec un `code` à la racine, comme `skill_version_already_installed` avec un HTTP 409 ou `hub_without_runtime_group` avec un HTTP 404, et le texte d'erreur du SDK se lit `HTTP <status>: <message> (<code>)`. Ces appels arrivent dans le SDK Python `0.5.15` et le SDK Node `0.3.15`. Pour les routes, le parcours dans l'application et le tableau des erreurs, consultez [Ajouter une compétence à un hub](/fr/manage/add-a-skill-to-a-hub/).

  

```python
skills = api.list_hub_skills("hub-id")  # HubSkillList; rows under .data
print(skills.source, skills.observed_at)
for skill in skills.data:
    print(skill.skill, skill.installed_version, skill.state, skill.update_available)

api.install_hub_skill("hub-id", "skill-weather", version="latest", wait=True)
api.update_hub_skill("hub-id", "skill-weather", version="1.2.0", wait=True)
api.remove_hub_skill("hub-id", "skill-weather", wait=True)
```

  
  

```ts
const skills = await api.listHubSkills("hub-id"); // { data, source, observed_at, ... }
console.log(skills.source, skills.observed_at);
for (const skill of skills.data) {
  console.log(skill.skill, skill.installed_version, skill.state, skill.update_available);
}

await api.installHubSkill("hub-id", "skill-weather", { version: "latest", wait: true });
await api.updateHubSkill("hub-id", "skill-weather", { version: "1.2.0", wait: true });
await api.removeHubSkill("hub-id", "skill-weather", { wait: true });
```

  

L'appel de liste renvoie l'enveloppe de la route : les rangées se trouvent sous `data`, et chacune contient `installed_version`, `latest_version`, `update_available` et un `state` parmi `pending`, `installed`, `failed`, `removing`, `drifted`, `quarantined` ou `unmanaged`. Chaque écriture renvoie l'opération acceptée avec `operation_id`, `skill`, `version`, `previous_version` et `state`. Go, Rust, Kotlin, Swift et .NET offrent aussi ces appels et l'historique, nommés selon le style de chaque langage; consultez leurs pages de SDK pour les options d'attente et de reprise.
