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

# Quickstart

> Faites votre premier appel authentifié à l'API Retriever et obtenez une liste d'entreprises en 5 minutes.

À la fin, vous aurez lancé l'agent Retriever par API et lu une vraie liste d'entreprises.

**Prérequis**

* Un compte Retriever avec quelques crédits.
* `curl` et [`jq`](https://jqlang.github.io/jq/) (`brew install jq`, `apt install jq`). Ou Node 18+, ou Python 3.9+ : voir [les scripts complets](#même-parcours-en-nodejs-ou-python).

<Steps>
  <Step title="Créer une clé API (1 min)">
    1. Ouvrez l'application Retriever.
    2. Allez dans **Paramètres → Clés API**.
    3. Cliquez sur **Créer une clé API**, puis confirmez avec **Créer la clé**.
    4. Copiez la clé `ret_live_…`. Elle n'est affichée qu'une fois.

    ```bash theme={null}
    export RETRIEVER_API_URL="https://api.retriever.run"
    export RETRIEVER_API_KEY="ret_live_..."
    ```
  </Step>

  <Step title="Vérifier la clé (15 s)">
    `/credits` n'a pas de préfixe `/v1`.

    ```bash theme={null}
    curl -s "$RETRIEVER_API_URL/credits" -H "Authorization: Bearer $RETRIEVER_API_KEY"
    ```

    Résultat attendu :

    ```json theme={null}
    { "remainingCredits": 842.5 }
    ```

    | Vous recevez             | Cause                                | Correction                                                              |
    | ------------------------ | ------------------------------------ | ----------------------------------------------------------------------- |
    | `not_authenticated`      | Clé absente, mal copiée ou révoquée. | Relancez `export RETRIEVER_API_KEY=…` sans espace ni guillemet en trop. |
    | `Could not resolve host` | Mauvaise base URL.                   | Vérifiez `RETRIEVER_API_URL`.                                           |
    | `remainingCredits` à `0` | Pas de crédits.                      | Rechargez avant l'étape suivante.                                       |
  </Step>

  <Step title="Lancer un run (15 s)">
    Une petite demande, pour un résultat rapide :

    ```bash theme={null}
    RUN_ID=$(curl -s -X POST "$RETRIEVER_API_URL/v1/runs" \
      -H "Authorization: Bearer $RETRIEVER_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "prompt": "Trouve 5 startups SaaS B2B basées à Lyon, avec leur site web.",
        "output": { "type": "tables", "tables": [{ "key": "startups" }] }
      }' | tee /dev/stderr | jq -r .id)
    echo "RUN_ID=$RUN_ID"
    ```

    Réponse `202 Accepted` (extrait) :

    ```json theme={null}
    {
      "id": "run_8f2c1a",
      "workspace_id": "ws_41b0",
      "conversation_id": "conv_77e2",
      "status": "queued",
      "links": { "self": "/v1/runs/run_8f2c1a" }
    }
    ```

    * `output` demande à l'agent de publier sa table sous la clé `startups`. Vous saurez exactement quoi lire à la dernière étape.
    * Retriever a créé un workspace et une conversation. Vous les verrez aussi dans l'application.
    * Si `RUN_ID` vaut `null`, lisez l'erreur affichée au-dessus.
  </Step>

  <Step title="Attendre la fin (1 à 3 min)">
    ```bash theme={null}
    for i in $(seq 1 40); do
      RUN=$(curl -s "$RETRIEVER_API_URL/v1/runs/$RUN_ID" -H "Authorization: Bearer $RETRIEVER_API_KEY")
      STATUS=$(echo "$RUN" | jq -r '.status // "error"')
      echo "$(date +%T) status=$STATUS phase=$(echo "$RUN" | jq -r '.progress.phase // "-"')"
      case "$STATUS" in
        queued|running|recovering) sleep 15 ;;
        *) break ;;
      esac
    done
    echo "$RUN" | jq '{status, message, error}'
    ```

    La boucle s'arrête sur un statut terminal, sur une erreur HTTP, ou après 10 minutes.

    ```json theme={null}
    {
      "status": "completed",
      "message": "J'ai trouvé 5 startups SaaS B2B lyonnaises et publié la table.",
      "error": null
    }
    ```

    | Résultat                        | Que faire                                                    |
    | ------------------------------- | ------------------------------------------------------------ |
    | `status=failed`                 | Lisez `error.message`. Vérifiez vos crédits.                 |
    | `status=error`                  | Réponse HTTP en erreur : `echo "$RUN"` affiche `error.code`. |
    | Toujours `running` après 10 min | Relancez la boucle : le run continue côté serveur.           |
  </Step>

  <Step title="Lire le résultat (15 s)">
    ```bash theme={null}
    curl -s "$RETRIEVER_API_URL/v1/runs/$RUN_ID/output/tables/startups/rows?limit=10" \
      -H "Authorization: Bearer $RETRIEVER_API_KEY" | jq '.items[].values'
    ```

    ```json theme={null}
    { "company_name": "Exemple SaaS", "website": "https://exemple.io" }
    { "company_name": "Autre Startup", "website": "https://autre.fr" }
    ```

    Les noms de colonnes dépendent de l'agent. Pour les imposer, ajoutez un `row_schema` : voir [Obtenir une table au format garanti](/recipes/guaranteed-table-format).
  </Step>
</Steps>

<Check>
  Vous avez fait votre premier appel API authentifié et obtenu une liste de prospects.
</Check>

## Même parcours en Node.js ou Python

<CodeGroup>
  ```js quickstart.mjs theme={null}
  const API = process.env.RETRIEVER_API_URL;
  const headers = {
    Authorization: `Bearer ${process.env.RETRIEVER_API_KEY}`,
    "Content-Type": "application/json",
  };

  async function call(path, init = {}) {
    const res = await fetch(`${API}${path}`, { ...init, headers });
    const body = await res.json();
    if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
    return body;
  }

  const created = await call("/v1/runs", {
    method: "POST",
    body: JSON.stringify({
      prompt: "Trouve 5 startups SaaS B2B basées à Lyon, avec leur site web.",
      output: { type: "tables", tables: [{ key: "startups" }] },
    }),
  });
  console.log("run", created.id);

  let run = created;
  for (let i = 0; ["queued", "running", "recovering"].includes(run.status); i++) {
    if (i >= 40) throw new Error("Toujours en cours après 10 min. Le run continue côté serveur.");
    await new Promise((r) => setTimeout(r, 15_000));
    run = await call(`/v1/runs/${created.id}`);
    console.log("status", run.status, run.progress?.phase ?? "");
  }
  if (run.status !== "completed") throw new Error(run.error?.message ?? run.status);

  const page = await call(`/v1/runs/${run.id}/output/tables/startups/rows?limit=10`);
  console.table(page.items.map((row) => row.values));
  ```

  ```python quickstart.py theme={null}
  import os, time, requests

  API = os.environ["RETRIEVER_API_URL"]
  HEADERS = {"Authorization": f"Bearer {os.environ['RETRIEVER_API_KEY']}"}

  def call(method, path, **kw):
      res = requests.request(method, f"{API}{path}", headers=HEADERS, timeout=30, **kw)
      body = res.json()
      if not res.ok:
          err = body["error"]
          raise RuntimeError(f"{res.status_code} {err['code']}: {err['message']}")
      return body

  run = call("POST", "/v1/runs", json={
      "prompt": "Trouve 5 startups SaaS B2B basées à Lyon, avec leur site web.",
      "output": {"type": "tables", "tables": [{"key": "startups"}]},
  })
  print("run", run["id"])

  for i in range(41):
      if run["status"] not in ("queued", "running", "recovering"):
          break
      if i == 40:
          raise RuntimeError("Toujours en cours après 10 min. Le run continue côté serveur.")
      time.sleep(15)
      run = call("GET", f"/v1/runs/{run['id']}")
      print("status", run["status"], (run.get("progress") or {}).get("phase"))

  if run["status"] != "completed":
      raise RuntimeError((run.get("error") or {}).get("message", run["status"]))

  page = call("GET", f"/v1/runs/{run['id']}/output/tables/startups/rows", params={"limit": 10})
  for row in page["items"]:
      print(row["values"])
  ```
</CodeGroup>

Lancez `node quickstart.mjs` (Node 18+) ou `python quickstart.py` (`pip install requests`).

## Et ensuite

* Imposer les colonnes du résultat : [Obtenir une table au format garanti](/recipes/guaranteed-table-format).
* Enrichir votre propre liste : [Enrichir une liste de votre CRM](/recipes/enrich-crm-list).
* Comprendre les runs, sorties et artefacts : [Runs](/concepts/runs).
