Error
Semua error dikembalikan dalam satu format - ok: false ditambah objek error:
{ "ok": false, "error": { "code": "INVALID_API_KEY", "message": "Invalid API key" }}code: kodeUPPER_SNAKE_CASEyang dapat dibaca mesin, stabil, tidak berubah tanpa kenaikan versi mayor. Lakukan switch berdasarkan field ini, bukan berdasarkanmessage.message: penjelasan yang dapat dibaca manusia, dalam bahasa Inggris. Teksnya bisa diperjelas tanpa kenaikan versi.details: opsional. UntukINVALID_INPUTini adalah array{ path, message }untuk setiap field yang gagal. UntukINVALID_FIELDsetiap elemen mendapat tambahanexpecteddengan nama field kanonis.docs: opsional, tautan ke bagian halaman ini jika kode tersebut memiliki penjelasan lebih rinci.request_id: hanya ditambahkan pada respons5xxdanBAD_JSON; sebutkan saat menghubungi dukungan.
Kode HTTP
Section titled “Kode HTTP”| Status | Arti |
|---|---|
200 OK | Berhasil |
400 Bad Request | JSON rusak, field hilang, atau validasi Zod gagal |
401 Unauthorized | X-Api-Key tidak ada atau tidak valid |
402 Payment Required | Dibutuhkan paket / pack lebih tinggi, atau langganan tidak aktif |
403 Forbidden | Kunci valid, tetapi tidak memiliki hak (scope, origin, suspended) |
404 Not Found | Resource, kunci, atau job tidak ada |
422 Unprocessable Entity | Input valid, tetapi engine tidak dapat menghitung |
429 Too Many Requests | Rate limit terlampaui, kredit habis, atau spend-cap tercapai |
500 Internal Server Error | Error internal - di sisi kami, sebutkan request_id |
503 Service Unavailable | Gateway AI / antrean sementara tidak tersedia |
Kode error
Section titled “Kode error”Autentikasi (401)
Section titled “Autentikasi (401)”| Kode | Arti |
|---|---|
MISSING_API_KEY | Header X-Api-Key tidak dikirim |
INVALID_API_KEY | Kunci tidak ada atau sudah dicabut |
MISSING_BEARER | Skema Authorization: Bearer dipilih, tetapi token tidak ada |
WRONG_AUTH_METHOD | X-Api-Key dikirim ke /v1/me/* (khusus Bearer). Untuk memeriksa kunci - GET /v1/auth/keys/me; untuk panggilan API - /v1/* apa pun dengan X-Api-Key |
Hak akses (403)
Section titled “Hak akses (403)”| Kode | Arti |
|---|---|
INSUFFICIENT_SCOPE | Kunci tidak memiliki hak untuk aksi ini |
DOMAIN_MISMATCH / FORBIDDEN_ORIGIN | Origin permintaan tidak ada di allow-list kunci |
ENDPOINT_NOT_IN_SCOPE | Kunci dibatasi daftar endpoint (allowed_endpoints), dan path ini tidak ada di daftar. details menyebutkan daftarnya |
KEY_SUSPENDED | Kunci ditangguhkan |
Penagihan (402)
Section titled “Penagihan (402)”| Kode | Arti |
|---|---|
PLAN_UPGRADE_REQUIRED | Endpoint membutuhkan paket lebih tinggi atau add-on pack |
PLAN_PACK_MISMATCH | Endpoint termasuk dalam pack yang tidak dimiliki kunci |
SUBSCRIPTION_EXPIRED | Periode berbayar berakhir lebih dari 3 hari yang lalu. Selama 3 hari pertama setelah berakhir, permintaan masih dilayani menurut paket dan membawa header X-Subscription-Grace-Ends. details berisi expired_at, grace_ended_at, dan renew_url |
Rate limiting dan kredit (429)
Section titled “Rate limiting dan kredit (429)”| Kode | Arti |
|---|---|
RATE_LIMIT | Batas RPM terlampaui. Respons berisi header Retry-After: <sec> |
CREDITS_EXHAUSTED | Anggaran kredit bulanan habis |
SPEND_CAP_REACHED | Batas pengeluaran untuk endpoint AI tercapai |
KEY_BUDGET_EXHAUSTED | Kunci telah menghabiskan anggarannya sendiri (credits_cap_cycle). Kredit di akun mungkin masih tersisa: batasan ini khusus untuk kunci tersebut |
Validasi (400)
Section titled “Validasi (400)”| Kode | Arti |
|---|---|
INVALID_INPUT | Satu atau beberapa field gagal validasi Zod. details - array { path, message } |
INVALID_FIELD | Body berisi nama field pendek, bukan yang kanonis. Lihat di bawah |
MISSING_FIELDS | Field wajib tidak ada |
BAD_JSON | JSON rusak di body permintaan |
Contoh 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 titled “INVALID_FIELD”Endpoint chart hanya menerima nama field lengkap. Bentuk pendek ditolak dengan 400, bukan dibaca diam-diam:
| Dikirim | Field kanonis | Yang diharapkan |
|---|---|---|
lat | latitude | derajat desimal, utara positif |
lng, lon, long | longitude | derajat desimal, timur positif |
tz berisi angka, tzOffset, utcOffset, timezone_offset | timezoneOffset | jumlah jam dari UTC, mis. 5.75 |
tz berisi nama, timeZone, time_zone | timezone | nama zona IANA, mis. Europe/Kyiv, atau auto |
Respons mencantumkan semua field yang ditemukan sekaligus, sesuai urutan body permintaan, sehingga penggantian nama dapat dilakukan dalam satu kali jalan:
{ "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 menunjukkan path lengkap, jadi di synastry terlihat bagan milik siapa: chart1.lat, bukan sekadar lat.
Kode yang sama dikembalikan saat timezone tidak dapat diurai: nilai kosong, singkatan seperti EST (ini tetap -5 sepanjang tahun, jadi New York di bulan Juli akan meleset satu jam), nama yang tidak ada di basis data zona waktu, offset yang ditulis sebagai teks seperti +03:00, atau auto tanpa latitude dan longitude. Pesannya menyarankan apa yang harus dikirim sebagai gantinya, dan path menunjuk ke objeknya, misalnya chart2.timezone.
Dua hal yang perlu diperhatikan.
Ini bukan deprecation. Nama pendek tidak pernah menjadi bagian kontrak dan tidak pernah tercantum di /openapi.json sebagai field body. Hingga 2026-08-01 nama-nama itu tidak berfungsi, melainkan diabaikan diam-diam: koordinat memiliki default nol, sehingga bagan dihitung untuk 0°N 0°E pada UTC. Ascendant, rumah, dan semua turunannya salah, dan respons tidak memberitahukannya. Karena itu bentuk pendek tidak akan diterima kembali: dua nama untuk satu field selamanya, dan tz pun ambigu (angka atau nama zona).
point bersarang adalah hal lain. Di /v1/acg-zones, /v1/acg/by-category, /v1/ccg-analysis, dan /v1/eclipse-analysis objek point: { lat, lng } adalah nama field yang dideklarasikan, dan diterima.
Koordinat tidak ada: 400 mulai 2026-11-09
Section titled “Koordinat tidak ada: 400 mulai 2026-11-09”Nama field yang benar baru separuh urusan. Body tanpa latitude dan longitude juga menghasilkan 200, karena koordinat memiliki default nol, dan respons menggambarkan 0°N 0°E.
Hingga 2026-11-09 permintaan seperti itu tetap berjalan, tetapi respons membawa Deprecation: true, Sunset, Warning, dan field _warning di body. Mulai 2026-11-09 hasilnya 400 INVALID_INPUT dengan latitude is required, in decimal degrees.
latitude: 0, longitude: 0 yang eksplisit tetap valid: masalahnya ada pada field yang hilang, bukan pada nilainya. timezoneOffset tetap memiliki default nol, karena nol di sana berarti UTC. city tidak menggantikan koordinat: tidak ada yang melakukan geocoding untuknya. Pemeriksaan hanya diterapkan pada objek yang membawa date dan time sekaligus.
Error perhitungan (422)
Section titled “Error perhitungan (422)”| Kode | Arti |
|---|---|
CALCULATION_ERROR | Input valid, tetapi engine tidak dapat menghitung (misalnya, lintang kutub untuk Placidus). Coba Whole Sign / Equal atau tanggal lain. |
Server
Section titled “Server”| Kode | HTTP | Arti |
|---|---|---|
INTERNAL_ERROR | 500 | Error tak terduga. Kami mencatatnya dengan stack trace, sebutkan request_id |
GATEWAY_UNAVAILABLE / AI_UNAVAILABLE / LLM_UNAVAILABLE | 503 | Gateway AI tidak tersedia. Retry dengan exponential backoff |
QUEUE_UNAVAILABLE | 503 | Antrean tugas latar belakang tidak tersedia |
Penanganan di kode klien
Section titled “Penanganan di kode klien”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})` : ''}`); }}Lakukan switch berdasarkan code, bukan message. SDK resmi (@astroway/sdk, astroway) melempar subkelas error bertipe berdasarkan status HTTP (AuthenticationError, RateLimitError, BadRequestError …), jadi kamu tidak perlu menulis kode penanganannya.
Permintaan dukungan
Section titled “Permintaan dukungan”Untuk menghubungi kami, kirim ke support@astroway.info:
request_iddari respons (jika ini5xx)- Endpoint dan body JSON yang disingkat (tanpa secret)
- Perilaku yang diharapkan vs yang terjadi
- Zona waktu dan perkiraan waktu permintaan (UTC)
Jawaban - dalam SLA paketmu (48 jam Starter, 24 jam Pro, tersendiri untuk Enterprise).