Fehler
Alle Fehler werden in einem einheitlichen Format zurückgegeben - ok: false plus ein Objekt error:
{ "ok": false, "error": { "code": "INVALID_API_KEY", "message": "Invalid API key" }}code: maschinenlesbarer Code inUPPER_SNAKE_CASE, stabil, ändert sich nicht ohne Major-Versionssprung. Verzweige danach, nicht nachmessage.message: menschenlesbare Erklärung auf Englisch. Der Text kann ohne Versionssprung präzisiert werden.details: optional. FürINVALID_INPUTist das ein Array{ path, message }für jedes fehlgeschlagene Feld. BeiINVALID_FIELDkommt zu jedem Elementexpectedmit dem kanonischen Feldnamen hinzu.docs: optional, ein Link auf einen Abschnitt dieser Seite, wenn es für den Code eine ausführlichere Erklärung gibt.request_id: wird nur bei5xx- undBAD_JSON-Antworten hinzugefügt; gib ihn an, wenn du dich an den Support wendest.
HTTP-Codes
Abschnitt betitelt „HTTP-Codes“| Status | Bedeutung |
|---|---|
200 OK | Erfolg |
400 Bad Request | Fehlerhaftes JSON, fehlende Felder oder fehlgeschlagene Zod-Validierung |
401 Unauthorized | X-Api-Key fehlt oder ist ungültig |
402 Payment Required | Ein höherer Tarif / ein Pack ist erforderlich, oder das Abonnement ist inaktiv |
403 Forbidden | Der Schlüssel ist gültig, aber es fehlen Rechte (Scope, Origin, gesperrt) |
404 Not Found | Ressource, Schlüssel oder Job existiert nicht |
422 Unprocessable Entity | Die Eingabe ist gültig, aber die Engine konnte nicht rechnen |
429 Too Many Requests | Rate Limit überschritten, Credits oder Spend-Cap aufgebraucht |
500 Internal Server Error | Interner Fehler - auf unserer Seite, gib request_id an |
503 Service Unavailable | AI-Gateway / Warteschlange vorübergehend nicht verfügbar |
Error codes
Abschnitt betitelt „Error codes“Authentifizierung (401)
Abschnitt betitelt „Authentifizierung (401)“| Code | Bedeutung |
|---|---|
MISSING_API_KEY | Header X-Api-Key wurde nicht gesendet |
INVALID_API_KEY | Der Schlüssel existiert nicht oder wurde widerrufen |
MISSING_BEARER | Das Schema Authorization: Bearer wurde gewählt, aber das Token fehlt |
WRONG_AUTH_METHOD | An /v1/me/* (nur Bearer) wurde X-Api-Key gesendet. Zur Prüfung des Schlüssels - GET /v1/auth/keys/me; für API-Aufrufe - ein beliebiger /v1/* mit X-Api-Key |
Rechte (403)
Abschnitt betitelt „Rechte (403)“| Code | Bedeutung |
|---|---|
INSUFFICIENT_SCOPE | Der Schlüssel hat keine Rechte für diese Aktion |
DOMAIN_MISMATCH / FORBIDDEN_ORIGIN | Der Origin der Anfrage steht nicht in der Allow-List des Schlüssels |
ENDPOINT_NOT_IN_SCOPE | Der Schlüssel ist auf eine Liste von Endpunkten beschränkt (allowed_endpoints), und dieser Pfad steht nicht darin. details nennt die Liste |
KEY_SUSPENDED | Der Schlüssel ist gesperrt |
Abrechnung (402)
Abschnitt betitelt „Abrechnung (402)“| Code | Bedeutung |
|---|---|
PLAN_UPGRADE_REQUIRED | Der Endpunkt erfordert einen höheren Tarif oder ein Add-on-Pack |
PLAN_PACK_MISMATCH | Der Endpunkt gehört zu einem Pack, das der Schlüssel nicht hat |
SUBSCRIPTION_EXPIRED | Der bezahlte Zeitraum ist vor mehr als 3 Tagen abgelaufen. In den ersten 3 Tagen nach Ablauf werden Anfragen noch zum Tarif bedient und tragen den Header X-Subscription-Grace-Ends. details enthält expired_at, grace_ended_at und renew_url |
Rate Limiting und Credits (429)
Abschnitt betitelt „Rate Limiting und Credits (429)“| Code | Bedeutung |
|---|---|
RATE_LIMIT | RPM-Limit überschritten. Die Antwort enthält den Header Retry-After: <sec> |
CREDITS_EXHAUSTED | Das monatliche Credit-Budget ist aufgebraucht |
SPEND_CAP_REACHED | Das Ausgabenlimit für AI-Endpunkte ist erreicht |
KEY_BUDGET_EXHAUSTED | Der Schlüssel hat sein eigenes Budget (credits_cap_cycle) aufgebraucht. Auf dem Konto können dabei noch Credits übrig sein: Die Beschränkung betrifft genau diesen Schlüssel |
Validierung (400)
Abschnitt betitelt „Validierung (400)“| Code | Bedeutung |
|---|---|
INVALID_INPUT | Ein oder mehrere Felder haben die Zod-Validierung nicht bestanden. details - ein Array { path, message } |
INVALID_FIELD | Der Body enthält einen kurzen Feldnamen statt des kanonischen. Siehe unten |
MISSING_FIELDS | Ein Pflichtfeld fehlt |
BAD_JSON | Fehlerhaftes JSON im Body der Anfrage |
Beispiel für 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
Abschnitt betitelt „INVALID_FIELD“Chart-Endpunkte akzeptieren nur vollständige Feldnamen. Kurzformen werden mit 400 abgelehnt, statt stillschweigend gelesen zu werden:
| Gesendet | Kanonisches Feld | Was erwartet wird |
|---|---|---|
lat | latitude | Dezimalgrad, Norden positiv |
lng, lon, long | longitude | Dezimalgrad, Osten positiv |
tz mit einer Zahl, tzOffset, utcOffset, timezone_offset | timezoneOffset | Stunden gegenüber UTC als Zahl, z. B. 5.75 |
tz mit einem Namen, timeZone, time_zone | timezone | Name einer IANA-Zone, z. B. Europe/Kyiv, oder auto |
Die Antwort listet alle gefundenen Felder auf einmal auf, in der Reihenfolge des Anfrage-Bodys, sodass die Umbenennung in einem Durchgang erledigt ist:
{ "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 gibt den vollständigen Pfad an, in der Synastrie ist also sichtbar, um wessen Horoskop es geht: chart1.lat, nicht einfach lat.
Derselbe Code kommt zurück, wenn sich timezone nicht auswerten lässt: ein leerer Wert, eine Abkürzung wie EST (das sind feste -5 das ganze Jahr, New York im Juli läge also eine Stunde daneben), ein Name, den es in der Zeitzonendatenbank nicht gibt, ein als Text geschriebener Versatz wie +03:00 oder auto ohne latitude und longitude. Die Meldung sagt, was stattdessen zu senden ist, und path zeigt auf das Objekt, zum Beispiel chart2.timezone.
Zwei Dinge sind zu beachten.
Das ist keine Deprecation. Die Kurznamen waren nie Teil des Vertrags und tauchten in /openapi.json nicht als Body-Felder auf. Bis zum 2026-08-01 funktionierten sie nicht, sondern wurden stillschweigend ignoriert: Die Koordinaten haben den Standardwert null, daher wurde das Horoskop für 0°N 0°E in UTC berechnet. Aszendent, Häuser und alles davon Abgeleitete waren falsch, und die Antwort teilte das nicht mit. Deshalb werden die Kurzformen nicht wieder akzeptiert: zwei Namen für ein Feld für immer, und tz ist obendrein mehrdeutig (Zahl oder Zonenname).
Ein verschachteltes point ist etwas anderes. In /v1/acg-zones, /v1/acg/by-category, /v1/ccg-analysis und /v1/eclipse-analysis sind im Objekt point: { lat, lng } das deklarierte Feldnamen, und sie gehen durch.
Fehlende Koordinaten: 400 ab 2026-11-09
Abschnitt betitelt „Fehlende Koordinaten: 400 ab 2026-11-09“Der richtige Feldname ist nur die halbe Miete. Ein Body ohne latitude und longitude lieferte ebenfalls 200, weil die Koordinaten den Standardwert null hatten, und die Antwort beschrieb 0°N 0°E.
Bis zum 2026-11-09 funktioniert eine solche Anfrage, aber die Antwort trägt Deprecation: true, Sunset, Warning und das Feld _warning im Body. Ab dem 2026-11-09 ist es 400 INVALID_INPUT mit latitude is required, in decimal degrees.
Explizite latitude: 0, longitude: 0 bleiben gültig: Es geht um das fehlende Feld, nicht um den Wert. timezoneOffset behält den Standardwert null, denn null bedeutet dort UTC. city ersetzt keine Koordinaten: Niemand geokodiert es. Die Prüfung gilt nur für Objekte, die gleichzeitig date und time tragen.
Berechnungsfehler (422)
Abschnitt betitelt „Berechnungsfehler (422)“| Code | Bedeutung |
|---|---|
CALCULATION_ERROR | Die Eingabe ist gültig, aber die Engine konnte nicht rechnen (zum Beispiel eine polare Breite für Placidus). Versuche Whole Sign / Equal oder ein anderes Datum. |
Serverfehler
Abschnitt betitelt „Serverfehler“| Code | HTTP | Bedeutung |
|---|---|---|
INTERNAL_ERROR | 500 | Unerwarteter Fehler. Wir loggen ihn mit Stack Trace, gib request_id an |
GATEWAY_UNAVAILABLE / AI_UNAVAILABLE / LLM_UNAVAILABLE | 503 | AI-Gateway nicht verfügbar. Retry mit exponentiellem Backoff |
QUEUE_UNAVAILABLE | 503 | Die Warteschlange für Hintergrundaufgaben ist nicht verfügbar |
Behandlung im Client-Code
Abschnitt betitelt „Behandlung im Client-Code“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})` : ''}`); }}Verzweige nach code, nicht nach message. Die offiziellen SDKs (@astroway/sdk, astroway) werfen typisierte Fehlerunterklassen nach HTTP-Status (AuthenticationError, RateLimitError, BadRequestError …), du musst den Behandlungscode also nicht selbst schreiben.
Supportanfrage
Abschnitt betitelt „Supportanfrage“Sende für eine Anfrage an support@astroway.info:
request_idaus der Antwort (falls es ein5xxist)- Endpunkt und gekürzten JSON-Body (ohne Geheimnisse)
- Erwartetes vs. tatsächliches Verhalten
- Zeitzone und ungefähre Zeit der Anfrage (UTC)
Die Antwort kommt innerhalb des SLA deines Plans (48 Std. Starter, 24 Std. Pro, individuell für Enterprise).