Erreurs
Toutes les erreurs sont renvoyées dans un format unique: ok: false plus un objet error:
{ "ok": false, "error": { "code": "INVALID_API_KEY", "message": "Invalid API key" }}code: codeUPPER_SNAKE_CASElisible par machine, stable, il ne change pas sans version majeure. Faites votre switch dessus, pas surmessage.message: explication lisible par un humain, en anglais. Le texte peut être précisé sans changement de version.details: facultatif. PourINVALID_INPUT, c’est un tableau{ path, message }pour chaque champ en échec. PourINVALID_FIELD, chaque élément reçoit en plusexpectedavec le nom canonique du champ.docs: facultatif, lien vers la section de cette page lorsque le code a une explication plus détaillée.request_id: ajouté uniquement aux réponses5xxetBAD_JSON; citez-le lorsque vous contactez le support.
Codes HTTP
Section intitulée « Codes HTTP »| Statut | Signification |
|---|---|
200 OK | Succès |
400 Bad Request | JSON invalide, champs manquants ou échec de la validation Zod |
401 Unauthorized | X-Api-Key absente ou invalide |
402 Payment Required | Un plan / pack supérieur est nécessaire, ou l’abonnement est inactif |
403 Forbidden | Clé valide, mais sans les droits (scope, origin, suspended) |
404 Not Found | La ressource, la clé ou le job n’existe pas |
422 Unprocessable Entity | Entrée valide, mais le moteur n’a pas pu calculer |
429 Too Many Requests | Rate limit dépassée, crédits ou spend-cap épuisés |
500 Internal Server Error | Erreur interne, de notre côté, citez le request_id |
503 Service Unavailable | Passerelle IA / file d’attente temporairement indisponibles |
Codes d’erreur
Section intitulée « Codes d’erreur »Authentification (401)
Section intitulée « Authentification (401) »| Code | Signification |
|---|---|
MISSING_API_KEY | L’en-tête X-Api-Key n’a pas été envoyé |
INVALID_API_KEY | La clé n’existe pas ou a été révoquée |
MISSING_BEARER | Le schéma Authorization: Bearer a été choisi, mais le jeton est absent |
WRONG_AUTH_METHOD | X-Api-Key envoyée sur /v1/me/* (Bearer uniquement). Pour vérifier une clé: GET /v1/auth/keys/me; pour les appels API: n’importe quel /v1/* avec X-Api-Key |
Droits (403)
Section intitulée « Droits (403) »| Code | Signification |
|---|---|
INSUFFICIENT_SCOPE | La clé n’a pas les droits pour cette action |
DOMAIN_MISMATCH / FORBIDDEN_ORIGIN | L’origine de la requête ne figure pas dans l’allow-list de la clé |
ENDPOINT_NOT_IN_SCOPE | La clé est limitée à une liste d’endpoints (allowed_endpoints), et ce chemin n’y figure pas. details cite la liste |
KEY_SUSPENDED | La clé est suspendue |
Facturation (402)
Section intitulée « Facturation (402) »| Code | Signification |
|---|---|
PLAN_UPGRADE_REQUIRED | L’endpoint nécessite un plan supérieur ou un pack add-on |
PLAN_PACK_MISMATCH | L’endpoint fait partie d’un pack absent de la clé |
SUBSCRIPTION_EXPIRED | La période payée s’est terminée il y a plus de 3 jours. Pendant les 3 premiers jours après l’expiration, les requêtes sont encore servies selon le plan et portent l’en-tête X-Subscription-Grace-Ends. details contient expired_at, grace_ended_at et renew_url |
Rate limiting et crédits (429)
Section intitulée « Rate limiting et crédits (429) »| Code | Signification |
|---|---|
RATE_LIMIT | Limite RPM dépassée. La réponse contient l’en-tête Retry-After: <sec> |
CREDITS_EXHAUSTED | Le budget mensuel de crédits est épuisé |
SPEND_CAP_REACHED | La limite de dépenses sur les endpoints IA est atteinte |
KEY_BUDGET_EXHAUSTED | La clé a épuisé son propre budget (credits_cap_cycle). Il peut encore rester des crédits sur le compte: la restriction concerne uniquement cette clé |
Validation (400)
Section intitulée « Validation (400) »| Code | Signification |
|---|---|
INVALID_INPUT | Un ou plusieurs champs ont échoué à la validation Zod. details est un tableau { path, message } |
INVALID_FIELD | Le corps contient un nom de champ abrégé au lieu du nom canonique. Voir ci-dessous |
MISSING_FIELDS | Un champ obligatoire est absent |
BAD_JSON | JSON invalide dans le corps de la requête |
Exemple de 400:
{ "ok": false, "error": { "code": "INVALID_INPUT", "message": "Validation failed: date: Invalid input: expected string, received undefined", "details": [ { "path": "date", "message": "Invalid input: expected string, received undefined" }, { "path": "time", "message": "Invalid input: expected string, received undefined" } ] }}INVALID_FIELD
Section intitulée « INVALID_FIELD »Les endpoints de carte n’acceptent que les noms de champs complets. Les formes abrégées sont rejetées avec un 400 au lieu d’être lues en silence:
| Envoyé | Champ canonique | Ce qui est attendu |
|---|---|---|
lat | latitude | degrés décimaux, nord positif |
lng, lon, long | longitude | degrés décimaux, est positif |
tz avec un nombre, tzOffset, utcOffset, timezone_offset | timezoneOffset | nombre d’heures par rapport à UTC, par ex. 5.75 |
tz avec un nom, timeZone, time_zone | timezone | nom de zone IANA, par ex. Europe/Kyiv, ou auto |
La réponse liste tous les champs trouvés en une seule fois, dans l’ordre du corps de la requête, le renommage se fait donc en une seule passe:
{ "ok": false, "error": { "code": "INVALID_FIELD", "message": "Unsupported fields: \"tz\", \"lat\", \"lng\". Rename them to \"timezoneOffset\", \"latitude\", \"longitude\". See details for what each one expects.", "details": [ { "path": "tz", "expected": "timezoneOffset", "message": "numeric hours from UTC, e.g. 5.75; a zone name goes in timezone" }, { "path": "lat", "expected": "latitude", "message": "decimal degrees, north positive" }, { "path": "lng", "expected": "longitude", "message": "decimal degrees, east positive" } ], "docs": "https://api.astroway.info/en/errors/#invalid_field" }}path indique le chemin complet, donc en synastrie on voit de quelle carte il s’agit: chart1.lat, et pas simplement lat.
Le même code est renvoyé lorsque timezone ne peut pas être analysé: valeur vide, abréviation comme EST (c’est un décalage fixe de -5 toute l’année, donc New York en juillet aura une heure d’erreur), nom absent de la base des fuseaux horaires, décalage écrit en texte comme +03:00, ou auto sans latitude ni longitude. Le message indique quoi envoyer à la place, et path pointe vers l’objet, par exemple chart2.timezone.
Deux points à prendre en compte.
Ce n’est pas une dépréciation. Les noms abrégés n’ont jamais fait partie du contrat et n’apparaissaient pas dans /openapi.json comme champs du corps. Avant le 2026-08-01, ils ne fonctionnaient pas, mais étaient ignorés en silence: les coordonnées valent zéro par défaut, donc la carte était calculée pour 0°N 0°E en UTC. L’ascendant, les maisons et tout ce qui en découle étaient faux, et la réponse ne le signalait pas. C’est pourquoi les formes abrégées ne seront pas réacceptées: deux noms pour un même champ pour toujours, et tz est en plus ambigu (nombre ou nom de zone).
Un point imbriqué, c’est autre chose. Dans /v1/acg-zones, /v1/acg/by-category, /v1/ccg-analysis et /v1/eclipse-analysis, l’objet point: { lat, lng } utilise des noms de champs déclarés, et ils sont acceptés.
Coordonnées absentes: 400 à partir du 2026-11-09
Section intitulée « Coordonnées absentes: 400 à partir du 2026-11-09 »Le bon nom de champ n’est que la moitié du travail. Un corps sans latitude ni longitude renvoyait lui aussi 200, car les coordonnées valaient zéro par défaut, et la réponse décrivait 0°N 0°E.
Jusqu’au 2026-11-09, une telle requête fonctionne, mais la réponse porte Deprecation: true, Sunset, Warning et le champ _warning dans le corps. À partir du 2026-11-09, ce sera 400 INVALID_INPUT avec latitude is required, in decimal degrees.
Des valeurs explicites latitude: 0, longitude: 0 restent valides: le problème est le champ absent, pas la valeur. timezoneOffset garde zéro par défaut, car zéro y signifie UTC. city ne remplace pas les coordonnées: personne ne le géocode. La vérification ne s’applique qu’aux objets qui portent à la fois date et time.
Erreurs de calcul (422)
Section intitulée « Erreurs de calcul (422) »| Code | Signification |
|---|---|
CALCULATION_ERROR | Entrée valide, mais le moteur n’a pas pu calculer (par exemple, une latitude polaire pour Placidus). Essayez Whole Sign / Equal ou une autre date. |
Erreurs serveur
Section intitulée « Erreurs serveur »| Code | HTTP | Signification |
|---|---|---|
INTERNAL_ERROR | 500 | Erreur inattendue. Nous la journalisons avec la stack trace, citez le request_id |
GATEWAY_UNAVAILABLE / AI_UNAVAILABLE / LLM_UNAVAILABLE | 503 | Passerelle IA indisponible. Retry avec backoff exponentiel |
QUEUE_UNAVAILABLE | 503 | La file des tâches d’arrière-plan est indisponible |
Traitement dans le code client
Section intitulée « Traitement dans le code client »type ApiError = { ok: false; error: { code: string; message: string; details?: unknown; request_id?: string; };};
async function chart(input: ChartInput) { const res = await fetch('https://api.astroway.info/v1/chart', { method: 'POST', headers: { 'X-Api-Key': process.env.ASTROWAY_API_KEY!, 'Content-Type': 'application/json', }, body: JSON.stringify(input), });
const body = await res.json(); if (!body.ok) { throw new AstrowayError(body.error.code, body.error.message, body.error.request_id); }
return body.data;}
class AstrowayError extends Error { constructor( public code: string, message: string, public requestId?: string, ) { super(`[${code}] ${message}${requestId ? ` (request_id=${requestId})` : ''}`); }}Faites votre switch sur code, pas sur message. Les SDK officiels (@astroway/sdk, astroway) lèvent des sous-classes d’erreurs typées selon le statut HTTP (AuthenticationError, RateLimitError, BadRequestError …), vous n’aurez donc pas à écrire le code de traitement.
Demande de support
Section intitulée « Demande de support »Pour nous contacter, envoyez à support@astroway.info:
- Le
request_idde la réponse (s’il s’agit d’un5xx) - L’endpoint et le corps JSON abrégé (sans secrets)
- Le comportement attendu vs le comportement réel
- Le fuseau horaire et l’heure approximative de la requête (UTC)
Réponse dans le cadre du SLA de votre plan (48 h pour Starter, 24 h pour Pro, sur mesure pour Enterprise).