Ir al contenido
AstroWay/api v2.254.12 · es
todos los sistemas funcionando con normalidad

Errores

Todos los errores se devuelven en un formato único: ok: false más un objeto error:

{
"ok": false,
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid API key"
}
}
  • code: código legible por máquina en UPPER_SNAKE_CASE, estable, no cambia sin un bump de versión major. Haz el switch sobre él, no sobre message.
  • message: explicación legible por humanos, en inglés. El texto puede precisarse sin bump de versión.
  • details: opcional. Para INVALID_INPUT es un array { path, message } con cada campo que falló. Para INVALID_FIELD se añade a cada elemento expected con el nombre canónico del campo.
  • docs: opcional, enlace a la sección de esta página cuando hay una explicación más detallada del código.
  • request_id: se añade solo a las respuestas 5xx y BAD_JSON; cítalo al contactar con soporte.
EstadoSignificado
200 OKÉxito
400 Bad RequestJSON roto, campos que faltan o validación Zod fallida
401 UnauthorizedX-Api-Key ausente o no válido
402 Payment RequiredHace falta un plan o pack superior, o la suscripción no está activa
403 ForbiddenLa clave es válida, pero no tiene permisos (scope, origin, suspended)
404 Not FoundEl recurso, la clave o el job no existe
422 Unprocessable EntityLa entrada es válida, pero el motor no pudo calcular
429 Too Many RequestsSe ha superado el rate limit, se han agotado los créditos o el spend-cap
500 Internal Server ErrorError interno, de nuestro lado; cita el request_id
503 Service UnavailableLa pasarela de IA / la cola no están disponibles temporalmente
CódigoSignificado
MISSING_API_KEYNo se ha enviado la cabecera X-Api-Key
INVALID_API_KEYLa clave no existe o está revocada
MISSING_BEARERSe eligió el esquema Authorization: Bearer, pero falta el token
WRONG_AUTH_METHODSe envió X-Api-Key a /v1/me/* (solo Bearer). Para comprobar una clave, GET /v1/auth/keys/me; para las llamadas a la API, cualquier /v1/* con X-Api-Key
CódigoSignificado
INSUFFICIENT_SCOPELa clave no tiene permisos para esta acción
DOMAIN_MISMATCH / FORBIDDEN_ORIGINEl origin de la petición no está en la allow-list de la clave
ENDPOINT_NOT_IN_SCOPELa clave está limitada a una lista de endpoints (allowed_endpoints) y esta ruta no está en ella. details indica la lista
KEY_SUSPENDEDLa clave está suspendida
CódigoSignificado
PLAN_UPGRADE_REQUIREDEl endpoint requiere un plan superior o un pack add-on
PLAN_PACK_MISMATCHEl endpoint forma parte de un pack que la clave no tiene
SUBSCRIPTION_EXPIREDEl periodo pagado terminó hace más de 3 días. Durante los 3 primeros días tras el vencimiento las peticiones se siguen atendiendo según el plan y llevan la cabecera X-Subscription-Grace-Ends. details contiene expired_at, grace_ended_at y renew_url
CódigoSignificado
RATE_LIMITSe ha superado el límite de RPM. La respuesta contiene la cabecera Retry-After: <sec>
CREDITS_EXHAUSTEDSe ha agotado el presupuesto mensual de créditos
SPEND_CAP_REACHEDSe ha alcanzado el límite de gasto en endpoints de IA
KEY_BUDGET_EXHAUSTEDLa clave ha agotado su propio presupuesto (credits_cap_cycle). La cuenta puede seguir teniendo créditos: la restricción afecta solo a esta clave
CódigoSignificado
INVALID_INPUTUno o varios campos no han pasado la validación Zod. details es un array { path, message }
INVALID_FIELDEl cuerpo contiene un nombre de campo corto en lugar del canónico. Ver más abajo
MISSING_FIELDSFalta un campo obligatorio
BAD_JSONJSON roto en el cuerpo de la petición

Ejemplo 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" }
]
}
}

Los endpoints de cartas solo aceptan nombres de campo completos. Las formas cortas se rechazan con 400, en lugar de leerse en silencio:

EnviadoCampo canónicoQué se espera
latlatitudegrados decimales, norte positivo
lng, lon, longlongitudegrados decimales, este positivo
tz con un número, tzOffset, utcOffset, timezone_offsettimezoneOffsetnúmero de horas desde UTC, p. ej. 5.75
tz con un nombre, timeZone, time_zonetimezonenombre de zona IANA, p. ej. Europe/Kyiv, o auto

La respuesta enumera todos los campos encontrados de una vez, en el orden del cuerpo de la petición, así que el renombrado se hace en una sola pasada:

{
"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 indica la ruta completa, así que en synastry se ve de quién es la carta: chart1.lat, no solo lat.

El mismo código se devuelve cuando timezone no se puede interpretar: un valor vacío, una abreviatura como EST (que es un -5 fijo todo el año, así que Nueva York en julio saldría con una hora de error), un nombre que no está en la base de husos horarios, un desfase escrito como texto, como +03:00, o auto sin latitude ni longitude. El mensaje sugiere qué enviar en su lugar, y path apunta al objeto, por ejemplo chart2.timezone.

Dos cosas a tener en cuenta.

No es una deprecación. Los nombres cortos nunca formaron parte del contrato ni figuraron en /openapi.json como campos del cuerpo. Hasta el 2026-08-01 no funcionaban, sino que se ignoraban en silencio: las coordenadas tienen cero por defecto, así que la carta se calculaba para 0°N 0°E en UTC. El ascendente, las casas y todo lo que deriva de ellos eran incorrectos, y la respuesta no lo decía. Por eso las formas cortas no se vuelven a aceptar: dos nombres para un mismo campo para siempre, y además tz es ambiguo (número o nombre de zona).

Un point anidado es otra cosa. En /v1/acg-zones, /v1/acg/by-category, /v1/ccg-analysis y /v1/eclipse-analysis, el objeto point: { lat, lng } usa nombres de campo declarados, y se aceptan.

Coordenadas ausentes: 400 desde el 2026-11-09

Sección titulada «Coordenadas ausentes: 400 desde el 2026-11-09»

El nombre de campo correcto es la mitad del asunto. Un cuerpo sin latitude ni longitude también daba 200, porque las coordenadas tenían cero por defecto, y la respuesta describía 0°N 0°E.

Hasta el 2026-11-09 una petición así funciona, pero la respuesta lleva Deprecation: true, Sunset, Warning y el campo _warning en el cuerpo. A partir del 2026-11-09 es 400 INVALID_INPUT con latitude is required, in decimal degrees.

latitude: 0, longitude: 0 explícitos siguen siendo válidos: el problema es el campo ausente, no el valor. timezoneOffset conserva el cero por defecto, porque ahí cero significa UTC. city no sustituye a las coordenadas: nadie lo geocodifica. La comprobación se aplica solo a los objetos que llevan a la vez date y time.

CódigoSignificado
CALCULATION_ERRORLa entrada es válida, pero el motor no pudo calcular (por ejemplo, una latitud polar con Placidus). Prueba con Whole Sign / Equal o con otra fecha.
CódigoHTTPSignificado
INTERNAL_ERROR500Error inesperado. Lo registramos con el stack trace; cita el request_id
GATEWAY_UNAVAILABLE / AI_UNAVAILABLE / LLM_UNAVAILABLE503La pasarela de IA no está disponible. Reintenta con backoff exponencial
QUEUE_UNAVAILABLE503La cola de tareas en segundo plano no está disponible
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})` : ''}`);
}
}

Haz el switch sobre code, no sobre message. Los SDK oficiales (@astroway/sdk, astroway) lanzan subclases de error tipadas según el estado HTTP (AuthenticationError, RateLimitError, BadRequestError …), así que no tendrás que escribir el código de tratamiento.

Para contactar, envía a support@astroway.info:

  1. El request_id de la respuesta (si es un 5xx)
  2. El endpoint y el body JSON abreviado (sin secretos)
  3. Comportamiento esperado frente al real
  4. La zona horaria y la hora aproximada de la petición (UTC)

La respuesta llega dentro del SLA de tu plan (48 h Starter, 24 h Pro, propio para Enterprise).

¿Útil?
Sugerir edición

Última actualización: