Authentication and API Keys
Cosmic Ephemeris deliberately separates calculation credentials from dashboard sessions. API keys authorize server-to-server calculations; a protected browser session authorizes account-management routes.
API keys
Every /api/astro/* endpoint requires one 64-character hexadecimal API key.
Send it using the preferred Bearer header:
Authorization: Bearer YOUR_API_KEY
The equivalent header below is also supported:
x-api-key: YOUR_API_KEY
Secret-handling boundary
Call Cosmic Ephemeris from your backend. Never place an account API key in browser JavaScript, a mobile bundle, analytics, a public repository, or a URL. Production CORS is restricted to Cosmic Ephemeris's own website and is not a client-side secret-management mechanism.
Key lifecycle
- An account can have up to five active keys, each with a unique label.
- Each key can carry a project label, development/staging/production environment, exact endpoint scope, optional expiration, and optional standard-unit monthly budget.
- The dashboard returns plaintext only when a key is generated or regenerated.
- The database stores only a one-way SHA-256 digest, so the existing plaintext cannot be displayed again.
- Individual revocation affects only that key. The retained legacy regeneration action revokes every active key before creating one replacement.
- Generating or rotating a key requires your active dashboard session and a trusted Cosmic Ephemeris browser request.
- Password change or recovery revokes every active key; create replacements after signing in again.
- Per-key budgets are guardrails inside the account allowance, reset at the UTC month boundary, and apply to standard synchronous and batch calculations made with that key.
- Rotate immediately after suspected exposure.
Server-side request
curl https://api.cosmicephemeris.com/api/astro/birth-chart \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $COSMICEPHEMERIS_KEY" \
-d '{
"date": "2000-01-01",
"time": "12:00",
"timezone": "UTC",
"lat": 0,
"lon": 0
}'
Dashboard sessions
Successful signup creates an active account and fixed eight-hour server-side dashboard session in one transaction, then sends the browser directly to the dashboard. Legacy email verification uses the same eight-hour duration. Later login uses eight hours by default; selecting "Keep me signed in" creates a fixed 30-day session instead. Activity does not extend either expiry. The signed credential is set in a Secure, HttpOnly, SameSite cookie; responses do not expose it to JavaScript, and Cosmic Ephemeris does not store it in localStorage. Dashboard requests send the cookie automatically; protected account changes also carry exact approved-origin evidence and Cosmic Ephemeris's request marker. This session is not accepted by calculation endpoints. Logout, password change, and password reset revoke database-backed sessions. Five failed current-password confirmations revoke only the session making those attempts; the account itself is not locked, so its owner can sign in normally.
Durable batch jobs
/api/jobs uses the same server-side API key as calculation
routes. A job accepts one to ten mixed items from
birth-chart, natal-analysis,
panchang, vargas, vimshottari,
planetary-hours, lunar-nodes,
moon-phases, planetary-events,
house-ingresses, aspect-windows,
event-calendar, and natal-report.
Every submission requires an 8–128 character Idempotency-Key
containing letters, digits, period, underscore, colon, or hyphen. Reusing
the key with the identical normalized request returns the existing job;
reusing it with different content returns 409.
curl https://api.cosmicephemeris.com/api/jobs \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $COSMICEPHEMERIS_KEY" \
-H "Idempotency-Key: charts-20260925-001" \
-d '{"items":[{"operation":"birth-chart","input":{
"date":"2000-01-01","time":"12:00","timezone":"UTC",
"lat":0,"lon":0
}}]}'
For a bounded newline-delimited file, send one job item object per line
to POST /api/jobs/import. The body must be UTF-8
application/x-ndjson, no larger than 32 KiB, and contain
one to ten non-empty lines. Cosmic Ephemeris does not retain the uploaded file,
filename, or original bytes; it retains only the same normalized item
inputs and results as a JSON job for 24 hours.
curl https://api.cosmicephemeris.com/api/jobs/import \
-X POST \
-H "Content-Type: application/x-ndjson" \
-H "Authorization: Bearer $COSMICEPHEMERIS_KEY" \
-H "Idempotency-Key: bulk-20260926-001" \
--data-binary @jobs.ndjson
POST /api/jobscreates a job;202means queued and an identical replay returns200.POST /api/jobs/importcreates the same job from bounded NDJSON; CSV, multipart, URLs, and compressed uploads are not accepted.GET /api/jobslists the newest 20 unexpired jobs created by the exact authenticated API key.GET /api/jobs/{id}returns ordered item states and completed results only for that same key.DELETE /api/jobs/{id}cancels queued work or requests cancellation between running items only for that same key.- At most ten active jobs are allowed per account. Inputs and results expire after 24 hours.
- Moon-phase, planetary-event, house-ingress, aspect-window, and event-calendar jobs retain their synchronous search bounds and fixed 30-second worker timeout; natal-report jobs retain fact-only output and a fixed 15-second timeout.
- Every item retains the 256 KiB stored-result ceiling; inputs and results expire after 24 hours.
- Each item reserves one standard monthly unit immediately before execution. Polling, replaying, and cancellation do not reserve additional units.
- Each item requires its exact
astro:<operation>scope orastro:*through execution. GET /api/jobsreturns the exactsupported_operations,supported_import_media_types, andmax_import_byteslimits.
Job states are queued, running,
succeeded, partial, failed, or
cancelled. Clients should poll the returned
status_url with bounded backoff and must not submit a fresh
idempotency key merely because a network response was lost. A different or rotated key cannot access or replay the original job.
Signed job-completion webhooks
A signed-in account can configure up to five HTTPS destinations on the
Job Webhooks dashboard. Cosmic Ephemeris sends one
job.completed event when an owned job first reaches
succeeded, partial, failed, or
cancelled. The event contains status metadata and a job
status path only; it never contains job input or calculation results.
{"id":"DELIVERY_UUID","type":"job.completed","created_at":"2026-09-25T16:00:00.000Z","data":{"job":{"id":"JOB_UUID","state":"succeeded","item_count":2,"completed_count":2,"failed_count":0,"completed_at":"2026-09-25T16:00:01.000Z","status_url":"/api/jobs/JOB_UUID"}}}
The endpoint secret is shown only when the endpoint is created or its secret is rotated. Each POST carries:
X-Cosmic-Ephemeris-Event-Id: stable delivery UUID for deduplication.X-Cosmic-Ephemeris-Timestamp: Unix seconds for this attempt.X-Cosmic-Ephemeris-Signature:v1=plus hexadecimal HMAC-SHA256 over<timestamp>.<exact raw body>.
const crypto = require("node:crypto");
function verifyCosmicEphemerisWebhook(rawBody, headers, secret) {
const timestamp = headers["x-cosmic-ephemeris-timestamp"];
const supplied = headers["x-cosmic-ephemeris-signature"] || "";
if (!/^\d+$/.test(timestamp || "")) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = "v1=" + crypto.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(supplied);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Verify the raw bytes before parsing JSON, enforce a short timestamp tolerance, and deduplicate by event ID. Any 2xx response succeeds. Other outcomes retry on a bounded schedule for at most eight attempts. Cosmic Ephemeris follows no redirects, requires public-only IPv4 DNS on every attempt, and retains delivery state for about 25 hours. Secret rotation applies to future claims. Accept the previous secret only for a brief overlap because an attempt already in flight may finish with it.
The protected Job Webhooks dashboard also shows metadata-only delivery
history retained for 25 hours. GET /api/webhooks/deliveries
returns 25 newest records by default, supports a bounded opaque cursor
and optional endpoint filter, and consumes no calculation units. It
never returns receiver bodies, event payloads, job inputs/results,
endpoint URLs, leases, or signing secrets.
A signed-in account can pause future events without deleting the endpoint
by sending exact JSON {"job_completed_enabled":false} to
PATCH /api/webhooks/{endpoint_id}/preferences through the
same-origin dashboard session. Pause suppresses queued retries; one
request already in flight may finish within five seconds. Resume changes
only later job transitions—events missed while paused are never replayed—and
neither action rotates or discloses the signing secret.
Login endpoint
POST https://api.cosmicephemeris.com/auth/login
{
"email": "user@example.com",
"password": "your-password",
"turnstileToken": "TOKEN_FROM_THE_LOGIN_WIDGET"
}
Production login and signup both require a single-use Cloudflare Turnstile result bound to the correct widget action and Cosmic Ephemeris hostname. Use the hosted login form for dashboard access; API integrations should authenticate calculation requests with an API key.
Login response
{
"user": {
"id": "8dd9b117-803a-4571-9d09-998c8a799682",
"email": "user@example.com",
"first_name": "Example",
"last_name": "Developer",
"plan": "free"
}
}
Account protection
- At least 12 characters and no more than 72 UTF-8 bytes
- At least one letter and one number
- A valid Cloudflare Turnstile verification from the signup or login form
- Account activation is separate from confirmed ownership of the email address
New registration may be temporarily closed during deployment or maintenance. When it is open, successful signup creates the active account and protected session immediately and continues to the dashboard. Signup does not send a verification email and does not prove control of the entered address, so check the spelling carefully. Password recovery sent to that mailbox can later establish address ownership. The verification page remains only for accounts that were pending before this signup change.
Authentication errors
400invalid signup, verification, reset, or password-policy input401missing, malformed, revoked, or unknown API key; invalid dashboard credentials or session403inactive legacy account, disallowed browser mutation, or failed login/signup bot verification409the email is already active or the submitted legacy credentials do not match429quota, per-user concurrency, or edge rate/connection limit503closed registration or authentication concurrency/dependency failure; retry only when appropriate