# Suivre un scan

Où en est un scan. Interroge cette route toutes les 3 à 5 secondes jusqu'à `done` ou `failed` ; un scan rapide prend en général moins d'une minute.

```
GET https://api.rustine.io/v1/scans/{scan_id}
```

Permission OAuth : `scans:read` · une clé d'API les a toutes

## Paramètres de chemin

- `scan_id` (string, obligatoire) Le scan.

## Réponse (200 OK)

- `id` (string, obligatoire) L'identifiant du scan.
- `object` (string, obligatoire) Le type d'objet, toujours le même pour une route donnée.
- `target_id` (string, obligatoire) Le site ou le dépôt scanné.
- `kind` (string, obligatoire) `quick` (ce que tout visiteur voit), `audit` (ajoute des contrôles en lecture seule, sites prouvés seulement) ou `repository` (analyse d'un dépôt GitHub). (`quick`, `audit`, `repository`)
- `status` (string, obligatoire) Les scans tournent en arrière-plan : interroge jusqu'à `done` ou `failed`. (`queued`, `running`, `done`, `failed`)
- `score` (number | null, obligatoire) Le score sur 100, une fois terminé.
- `grade` (string | null, obligatoire) La note, une fois terminé. (`A`, `B`, `C`, `D`, `F`)
- `coverage` (number | null, obligatoire) La part des contrôles qui ont pu tourner (de 0 à 1), une fois terminé.
- `audit_fallback` (boolean, obligatoire) Un audit était demandé mais la preuve du site ne tenait plus : un scan rapide a tourné à la place, et aucun audit n'a été décompté.
- `reused` (boolean, obligatoire) Vrai quand la requête a reçu un scan existant au lieu d'un nouveau (un en cours, ou un du même type dans l'heure) ; rien n'a été décompté.
- `next_real_scan_at` (string | null, obligatoire) Avec `reused` pour un scan récent : quand un nouveau scan de ce type pourra partir.
- `created_at` (string, obligatoire) Quand il a été demandé (ISO 8601, UTC).
- `finished_at` (string | null, obligatoire) Quand il s'est terminé, `null` tant qu'il tourne.

## Exemples

### curl

```bash
# La clé reste dans une variable, jamais dans l'adresse
curl https://api.rustine.io/v1/scans/e7f9a1b3-5c7d-4e9f-b1a3-c5d7e9f1a3b5 \
  -H "Authorization: Bearer $RUSTINE_API_KEY"
```

### Node

```js
const res = await fetch(
  "https://api.rustine.io/v1/scans/e7f9a1b3-5c7d-4e9f-b1a3-c5d7e9f1a3b5",
  {
    headers: {
      Authorization: `Bearer ${process.env.RUSTINE_API_KEY}`,
    },
  },
)
const scan = await res.json()
```

### Python

```python
import os

import requests

scan = requests.get(
    "https://api.rustine.io/v1/scans/e7f9a1b3-5c7d-4e9f-b1a3-c5d7e9f1a3b5",
    headers={
        "Authorization": f"Bearer {os.environ['RUSTINE_API_KEY']}",
    },
).json()
```

### Réponse : 200 OK

```json
{
  "id": "e7f9a1b3-5c7d-4e9f-b1a3-c5d7e9f1a3b5",
  "object": "scan",
  "target_id": "8d2e4f6a-9b1c-4d3e-a5f7-0b2c4d6e8f1a",
  "kind": "audit",
  "status": "done",
  "score": 62,
  "grade": "C",
  "coverage": 0.94,
  "audit_fallback": false,
  "reused": false,
  "next_real_scan_at": null,
  "created_at": "2026-10-13T08:41:02.000Z",
  "finished_at": "2026-10-13T08:42:10.000Z"
}
```

## Erreurs

| Code | error.code | Ce qui se passe |
| --- | --- | --- |
| 401 | `authentication_required` | Aucune clé dans la requête. Passe-la dans l'en-tête `Authorization: Bearer rst_…`, jamais dans l'adresse. |
| 401 | `invalid_api_key` | La clé ou le jeton OAuth est faux, révoqué ou expiré. Vérifie qu'il est copié en entier, ou crée une nouvelle clé. |
| 402 | `api_plan_required` | L'espace est sur l'offre Gratuite. L'API vient avec Pro, ou à l'essai 14 jours sur Solo. |
| 402 | `api_trial_ended` | L'essai de 14 jours de Solo est terminé. Passe à Pro : tes clés remarchent aussitôt. |
| 403 | `scope_missing` | Le jeton OAuth n'a pas la permission que demande cette route (indiquée sur sa page). Reconnecte l'agent pour l'accorder. Une clé d'API a toutes les permissions. |
| 404 | `resource_not_found` | Rien avec cet identifiant dans l'espace de la clé. Un objet d'un autre espace répond pareil : son existence n'est jamais révélée. |
| 429 | `rate_limited` | Trop de requêtes pour cette clé (120 par minute). Attends `Retry-After` secondes. |
| 500 | `internal_error` | Une erreur de notre côté, signalée automatiquement. Réessaie plus tard ; donne le `Request-Id` au support si elle revient. |
| 503 | `service_unavailable` | Rustine est indisponible un instant. Réessaie avec la même `Idempotency-Key`. |

https://docs.rustine.io/api/errors
