Les conventions de l'API
Ce qui vaut partout, plutôt que répété sur chaque route.
L'enveloppe d'erreur
Toute erreur a la même forme.
{
"status": "error",
"message": "CREDITS_EXHAUSTED",
"messageDetail": "Not enough credits."
}message porte un code machine en majuscules, à lire dans votre code. messageDetail porte une phrase lisible, à montrer ou à journaliser. Ne branchez jamais votre logique sur messageDetail : c'est du texte, il peut changer.
La liste complète est sur la page Codes d'erreur.
Le request_id
Chaque réponse porte un en-tête x-request-id. C'est le seul élément exploitable si vous ouvrez un ticket : il permet de retrouver l'appel exact dans les journaux.
Les bibliothèques le placent dans chaque exception et dans chaque résultat.
except SpavikError as exc:
logger.error("appel refuse", code=exc.code, request_id=exc.request_id)L'idempotence
Les cinq opérations qui modifient quelque chose acceptent un en-tête Idempotency-Key : POST /v1/models, /predict, /outcomes, /refresh et POST /v1/forecast.
Rejouer le même appel avec la même clé renvoie la réponse déjà calculée, sans nouveau débit. C'est ce qui rend une reprise après coupure réseau sans danger : sans elle, vous choisiriez entre payer deux fois et perdre un résultat déjà payé.
curl -X POST "$SPAVIK_BASE_URL/v1/models/{id}/predict" \
-H "X-API-Key: $SPAVIK_API_KEY" \
-H 'Idempotency-Key: 6f1c8b90-...' \
-H 'Content-Type: application/json' -d '{"rows":[...]}'Tirez une clé par appel logique, pas par tentative : c'est en la rejouant telle quelle que vous êtes protégé. Les bibliothèques s'en chargent.
Deux codes s'y rapportent : IDEMPOTENCY_KEY_REUSED si vous réutilisez une clé pour un contenu différent, REQUEST_IN_PROGRESS si le premier appel n'a pas encore rendu sa réponse.
La pagination
Les listes se parcourent avec limit et offset, et rendent un objet pagination.
{
"data": [ ... ],
"pagination": { "total": 128, "limit": 50, "offset": 0, "has_more": true }
}| Route | limit par défaut | maximum |
|---|---|---|
GET /v1/models, /v1/api-keys | 50 | 200 |
GET /v1/requests | 100 | 500 |
Les bibliothèques masquent tout cela : models() est un itérateur qui va chercher les pages au fur et à mesure.
for model in spavik.models():
print(model.id)Les fenêtres de temps
Les routes qui lisent un historique acceptent from et to en dates ISO 8601, ou days pour une fenêtre glissante.
| Paramètre | Défaut | Maximum |
|---|---|---|
days | 30 | 365 |
GET /v1/requests accepte en plus status=error, qui ne garde que les échecs : de quoi retrouver un rejet survenu en production sans avoir à le reproduire.
Les nouvelles tentatives
Trois familles méritent une nouvelle tentative, et trois seulement : 429, les 5xx, et les pannes réseau. Une 4xx ne changera pas d'avis, la rejouer ne fait que perdre du temps.
L'API n'expose pas d'en-tête Retry-After à ce jour. Les bibliothèques attendent donc selon une progression exponentielle avec une part d'aléa, trois tentatives au maximum, et rejouent la même clé d'idempotence.
Les identifiants
Ils sont opaques et préfixés. Ne les analysez pas, ne les reconstruisez pas.
| Préfixe | Objet |
|---|---|
mdl_ | modèle |
ver_ | version d'un modèle |
whk_ | webhook |
sk-spv-api- | clé d'usage |
sk-spv-admin- | clé d'administration |
Les dates
Toutes les dates sont en ISO 8601, en UTC, avec le suffixe Z.