Integrate the Alatic Public Alerts API into my existing bot or server application. Inspect my project first and follow its language, framework, configuration, persistence and test conventions. Implement working code, not pseudocode. If I have no project, ask which platform/language and destination channel I want before creating one. Keep the API key in the server-side ALATIC_API_KEY environment variable or secret manager. Create only an empty/example configuration entry: never ask me to paste a real key into this chat, commit it, log it, put it in a URL, or expose it to browser code. Do not make a live authenticated request until I explicitly want to activate the subscription; the first request starts a monthly key's 30 days. Build a single non-overlapping polling worker, defaulting to one list request every 30 seconds. Budget list, pagination and tracked-alert detail requests together within 5 requests/minute per key; reserve the remaining request budget for tracked-alert detail checks and pagination, spreading extra checks across later minutes. Respect Retry-After; retry transient failures with capped exponential backoff and jitter. Use request timeouts and graceful shutdown. On 401, pause authenticated polling and report the configuration/renewal problem without exposing the key. Never interpret network errors, 403/5xx or rate limits as an outage ending. A Cloudflare 403/1010 is a configuration problem to report, not bypass. Persist alert IDs, destination message IDs, last known state and notification/delivery state across restarts. On the first sync, baseline existing alerts without flooding the destination with old posts or pings. On later polls post newly observed active alerts without a ping, update the same messages as statuses change, and reconcile interrupted sends to avoid duplicates. Ping at most once when notification_sent_at becomes non-null while the alert remains active. Do not implement a local five-minute timer as a substitute for the upstream recheck. Recheck tracked active IDs even after they leave the first list page. Follow opaque next_cursor values and restart pagination on invalid_cursor. For an authenticated detail 404 remove sensitive details or mark unavailable, never patched. Use the explicit patched or ended status to close messages. Only display the documented public fields. Never invent Goliath IDs, coordinates, Minecraft usernames, teleports, staff verification, hidden-tier information or a guarantee that a bot is online. The API provides public information only; embeds may use my application's style. Respect the no-key-sharing rule. Add meaningful tests for authentication errors, pagination, restart/deduplication, delayed ping delivery, status changes, detail 404, rate limits and temporary failures. Finish with setup steps and a list of files changed. Do not automatically send messages to a real channel as a test. Authoritative API reference (read fully): # Alatic Public Alerts API — v1 ## Quick start Connect your bot or server application to Alatic’s public region alerts. Base URL: `https://api.alatic.store` - Save your API key in the server-side `ALATIC_API_KEY` environment variable. - Request `/v1/alerts` with the Authorization header shown below. - Poll every 30 seconds and update your existing messages when an alert changes. API keys are separate from Discord rank keys. Monthly access lasts 30 days from the first authenticated request, including `/v1/me`. Lifetime keys have no scheduled expiry. To renew monthly access, replace the expired key with a new one. ## Authentication Send your complete, case-sensitive key in the header: ```http Authorization: Bearer ALATIC-YOUR_RANDOM_STRING ``` `ALATIC-YOUR_RANDOM_STRING` is a placeholder. New keys start with `ALATIC-`; previously issued keys still work unchanged. ```bash export ALATIC_API_KEY='ALATIC-YOUR_RANDOM_STRING' curl --fail-with-body https://api.alatic.store/v1/alerts \ -H "Authorization: Bearer $ALATIC_API_KEY" ``` Keep your key private and server-side. Never include it in a URL, browser code or public repository. Do not share or resell your key. ## Rate limit Each key allows `5 requests per minute`, shared across all authenticated endpoints and clients using that key. Poll the alert list every 30 seconds (2 requests per minute). Use the remaining budget for individual alert checks or pagination; spread additional checks across later minutes. Responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining`. If you receive HTTP 429, wait the number of seconds in `Retry-After` before retrying. Avoid overlapping polling loops. ## GET /v1/alerts Returns public alerts, newest first. - `limit`: page size, 1–100; defaults to 50. - `before`: use the previous response’s `next_cursor` to fetch the next page. Stop when it is null. ```json { "data": [{ "id": "018af922-9842-4c07-a7af-47f56de7a239", "region": "EU West", "status": "active", "published_at": "2026-10-19T12:00:00.000Z", "ended_at": null, "notification_sent_at": null }], "next_cursor": null } ``` - `id`: stable alert identifier. Use it to update the same message instead of creating duplicates. - `region`: Asia, NA East, NA West, EU Central, EU West or Oceania. - `status`: `active`, `patched` or `ended`. Active means the alert has not ended; it does not guarantee a Minecraft bot is online. - `published_at`: alert publication timestamp. - `ended_at`: closure timestamp, or null. - `notification_sent_at`: notification timestamp, or null while a notification is not yet available. All timestamps are UTC ISO 8601 strings. The API does not provide Goliath IDs, coordinates, Minecraft usernames, teleports or private alerts. ## Updating alerts and pings Post new alerts without a ping. Ping once only when `notification_sent_at` becomes non-null and `status` is still `active`. This follows Alatic’s delayed recheck; do not replace it with your own five-minute timer. When status becomes `patched` or `ended`, update the existing message. Save alert IDs, message IDs and sent-ping state so restarts do not create duplicate posts or pings. On first setup, baseline existing alerts instead of announcing old history. ## GET /v1/alerts/{id} Fetch one alert using its ID. The response is `{"data": {...}}` with the same alert fields. Recheck tracked active alerts even if they leave the first list page, within your shared request budget. A 404 means the alert is unknown or no longer public: remove its details or mark it unavailable. Do not label it patched unless its returned status is `patched`. ## GET /v1/me Check your key’s plan and expiry. This request activates an unused monthly key and counts toward the rate limit. ```json { "id": "your-key-id", "plan": "monthly", "activated_at": "2026-10-19T12:00:00.000Z", "expires_at": "2026-11-18T12:00:00.000Z" } ``` Lifetime keys return `expires_at: null`. ## Errors - 400: invalid query or cursor. Check parameters; restart pagination if the cursor is invalid. - 401: missing, invalid, expired or revoked key. Check your configuration or renew access. - 404: endpoint or public alert not found. - 405: use GET; other methods are unsupported. - 429: request limit reached. Wait for `Retry-After`. - 503: temporary issue. Retry with backoff. Network failures, rate limits and server errors do not mean an alert has ended. Keep the last known state marked as stale until a successful response. If access is blocked with HTTP 403, contact support. API v1 uses polling, not webhooks or streaming. ## Node.js example ```js const key = process.env.ALATIC_API_KEY; if (!key) throw new Error('Set ALATIC_API_KEY'); const response = await fetch('https://api.alatic.store/v1/alerts?limit=50', { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(10000) }); if (!response.ok) { // On 429, wait response.headers.get('Retry-After') seconds. throw new Error(`Alatic API returned HTTP ${response.status}`); } const { data, next_cursor } = await response.json(); for (const alert of data) { console.log(alert.id, alert.region, alert.status); // Create or update your message using the saved alert ID. } ``` This example makes one request. For continuous updates, use one sequential polling loop and keep all requests within the 5-per-minute limit.