Public install, private API key

Quave Pager API

Agents should install the Quave Pager skill instead of scraping this HTML page. This page is mainly a human-readable API guide and fallback reference.

Download The Apps

Install Quave Pager on Android and/or macOS, then create or verify your account and keep your API key in an approved secret store. Release assets are hosted in the public agent repository.

Latest Android APKQuavePager.apk
macOS automatic installcurl -fsSL https://pager.quave.ai/install-macos.sh | bash
macOS manual DMGQuavePager-macOS.dmg
macOS terminal zipQuavePager-macOS.zip
Latest releasequavedev/pager-agent/releases/latest
Android packageai.quave.alarm
macOS bundle IDai.quave.alarm.mac

The download links always point to the latest public release assets. Android may ask you to allow installs from your browser or file manager. macOS users have two polished paths: run the terminal installer for an automatic install into ~/Applications, or open the DMG and drag the Quave Pager icon into Applications. The public macOS DMG and zip are Developer ID signed, notarized, and stapled for direct download outside the Mac App Store.

  1. Android: download and install QuavePager.apk, then grant notifications, full-screen alerts, exact alarms, Do Not Disturb bypass, and unrestricted battery/background usage when prompted.
  2. macOS automatic: run curl -fsSL https://pager.quave.ai/install-macos.sh | bash, paste an API key, and enable launch-at-login in Preferences.
  3. macOS manual: download QuavePager-macOS.dmg, open it, drag Quave Pager into Applications, then open the app.
  4. Copy the generated API key only into QUAVE_PAGER_API_KEY for your agent environment or approved secret store.
  5. Run the agent dry-run before the first real page.

macOS Desktop Receiver

The macOS receiver is a native Swift/AppKit client that aims for Android-power parity: Keychain API-key storage, long-poll delivery, cached future alarms, local timers, listener sleep prevention while running, launch-at-login, configurable ringtone/snooze durations, and a full-screen always-on-top alarm with looping sound until dismissed or snoozed.

Automatic installcurl -fsSL https://pager.quave.ai/install-macos.sh | bash
Manual DMGQuavePager-macOS.dmg
Terminal zipQuavePager-macOS.zip
Sourcemacos/ in the Quave Pager repo
Local buildcd macos && swift build
Local app bundlecd macos && ./scripts/build-app.sh
DistributionDirect download after Developer ID signing and Apple notarization; no Mac App Store release is required.

Device priority metadata is platform-aware: macOS defaults to 10, future iOS to 20, and Android to 30. Android and macOS both expose delivery controls: ring all enabled devices at once, or use ordered escalation every 30 seconds so lower-priority numbers ring first and later devices join until someone dismisses or snoozes.

For AI Agents: Install The Skill First

If you are an AI agent reading this page, install the public skill package and follow its SKILL.md. The package CLI is the preferred interface for creating, listing, editing, snoozing, canceling, dismissing, and removing alarms.

Use --link for the result/action URL from the conversation. Use the AI conversation resume flags when the alarm should bring the user back to Codex, Claude Code, Cursor, or another agent. Native clients render that as a separate Resume AI conversation action.

Skill repoquavedev/pager-agent
Install commandnpx skills add quavedev/pager-agent --skill quave-pager -g -a '*'
API key env varQUAVE_PAGER_API_KEY
Machine metadata/.well-known/quave-pager.json

Do not paste API keys in chat, URLs, docs, logs, command arguments, or committed files. Keep them in an environment variable, secret manager, or the current process environment.

npx -y github:quavedev/pager-agent trigger --message "Look at Codex: I need your decision." --codex-thread-id "<thread-id>"
npx -y github:quavedev/pager-agent trigger --message "Claude Code is blocked." --claude-session "<session-id>" --ai-cwd "$PWD"
npx -y github:quavedev/pager-agent trigger --message "Review this PR." --link "https://github.com/example/repo/pull/123"
npx -y github:quavedev/pager-agent list
npx -y github:quavedev/pager-agent edit <alarm-id> --scheduled-at "2026-06-13 16:19:00" --time-zone "America/Campo_Grande" --status pending
npx -y github:quavedev/pager-agent remove <alarm-id>

1. Create an API Key

Install the Android app, create or verify your account, then copy the first API key shown by the app. Existing users can create, rotate, and revoke keys through /api/api-keys. The plaintext key is returned only once.

API key env varQUAVE_PAGER_API_KEY
Agent packagequavedev/pager-agent
OpenAPI/openapi.json

2. Choose Create Mode

POST /api/alarms supports three scheduling modes. Use exactly one mode per request.

ModeHow to send itWhen it rings
ASAPOmit scheduledAt and delaySeconds.Immediately, then expires after ttlSeconds.
RelativeSend delaySeconds, for example 300 for five minutes.Now plus the delay.
ScheduledSend scheduledAt plus timeZone for local time, or an ISO timestamp with an offset/Z.At the concrete timestamp.

Do not combine scheduledAt and delaySeconds; the API returns schedule_conflict.

3. Trigger ASAP

For an immediate alarm, omit scheduledAt and delaySeconds. The server records the alarm immediately and expires it after ttlSeconds, defaulting to 900 seconds.

export QUAVE_PAGER_API_KEY="<user-owned API key>"

curl -fsS -X POST https://pager.quave.ai/api/alarms \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Codex needs you",
    "body": "Look at Codex: I need your decision to continue.",
    "severity": "critical",
    "ttlSeconds": 900,
    "aiConversationResume": {
      "provider": "codex",
      "conversationId": "<thread-id>",
      "targets": [
        { "platforms": ["android", "ios", "web"], "kind": "url", "url": "https://chatgpt.com/codex", "label": "Open Codex" },
        { "platforms": ["macos"], "kind": "deeplink", "url": "codex://threads/<thread-id>", "label": "Open Codex app" }
      ],
      "fallbackInstructions": "Open Codex and resume this task."
    }
  }'

4. Relative Delay

For a relative alarm, send delaySeconds. Five minutes is 300. The API stores the computed scheduledAt timestamp in the response.

curl -fsS -X POST https://pager.quave.ai/api/alarms \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Five-minute follow-up",
    "body": "Look at Codex: five-minute follow-up.",
    "severity": "critical",
    "delaySeconds": 300,
    "ttlSeconds": 900,
    "aiConversationResume": {
      "provider": "codex",
      "conversationId": "<thread-id>",
      "targets": [
        { "platforms": ["android", "ios", "web"], "kind": "url", "url": "https://chatgpt.com/codex" },
        { "platforms": ["macos"], "kind": "deeplink", "url": "codex://threads/<thread-id>" }
      ]
    }
  }'

5. Schedule With Time Zone

For local wall-clock scheduling, send scheduledAt as YYYY-MM-DDTHH:mm:ss plus an IANA timeZone. If timeZone is omitted for a local timestamp, the server defaults to America/Campo_Grande.

Best practice for agents: always include the user's intended IANA time zone when scheduling by local time. Use an explicit offset or Z when scheduling in absolute UTC time.

curl -fsS -X POST https://pager.quave.ai/api/alarms \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Follow-up",
    "body": "Look at Codex: scheduled review time.",
    "severity": "critical",
    "scheduledAt": "YYYY-MM-DDT09:00:00",
    "timeZone": "America/Campo_Grande",
    "ttlSeconds": 900,
    "aiConversationResume": {
      "provider": "codex",
      "conversationId": "<thread-id>",
      "targets": [
        { "platforms": ["android", "ios", "web"], "kind": "url", "url": "https://chatgpt.com/codex" },
        { "platforms": ["macos"], "kind": "deeplink", "url": "codex://threads/<thread-id>" }
      ]
    }
  }'

Absolute timestamp alternative

{
  "scheduledAt": "YYYY-MM-DDT13:00:00Z",
  "ttlSeconds": 900
}

6. Payload Contract

FieldRequiredNotes
titleNoDefaults to Quave Pager.
bodyNoUse one concise sentence with the destination and blocker.
severityNoinfo, warning, or critical. Defaults to critical.
linkNoOptional http:// or https:// destination/result/action URL. The native app shows an open action. url is accepted as an alias. Do not use this field merely to resume the AI conversation.
aiConversationResumeNoOptional object that tells compatible native clients how to return to the agent/chat. It renders separately from link as Resume AI conversation.
scheduledAtNoISO timestamp. Local values use timeZone or the default America/Campo_Grande.
timeZoneNoValid IANA time zone. Recommended for local scheduling.
delaySecondsNoRelative scheduling. Do not combine with scheduledAt.
ttlSecondsNoAlarm delivery window after the scheduled time. Clamped from 30 seconds to 24 hours.
deviceIdNoOmit to page every registered device.

7. AI Conversation Resume

aiConversationResume is for the action that returns the user to the AI. It is intentionally separate from link, which is the useful result of the conversation. Each resume target declares the devices it supports so Android, iOS, macOS, web, or future clients can choose the safest native action.

FieldNotes
providercodex, claude-code, cursor, or other.
conversationIdOptional thread/session/chat identifier when the agent knows one.
targets[].platformsRequired list such as ["android"], ["macos"], or ["android","ios","web"].
targets[].kindurl, deeplink, copyCommand, or instructions.
fallbackInstructionsShort human fallback when no device-specific target is usable.

Android supports URL and instruction resume targets. macOS supports URL, approved deep links, copyable commands, and instructions. Registered devices also advertise capabilities.aiConversationResume plus capabilities.aiConversationResumeKinds.

{
  "aiConversationResume": {
    "provider": "claude-code",
    "conversationId": "<session-id>",
    "targets": [
      {
        "platforms": ["macos"],
        "kind": "copyCommand",
        "command": "claude --resume <session-id>",
        "cwd": "/path/to/repo",
        "label": "Copy Claude resume command"
      }
    ],
    "fallbackInstructions": "Open Claude Code in the repository and resume session <session-id>."
  }
}

8. Register And Manage Devices

Native clients register themselves with platform metadata. Use GET /api/delivery or GET /api/devices to inspect the account delivery rule, which receivers are active, and which specific device is currently ringing. Use POST /api/delivery to switch between all and ordered, PATCH /api/devices/:deviceId to rename a device, change priority, or disable a receiver, and DELETE /api/devices/:deviceId to logically remove a device without deleting history.

Every device registration and long-poll sync updates lastSeenAt. The long-poll response also includes stoppedAlarmIds so a dismiss, acknowledge, cancel, remove, snooze, or per-device remote dismiss action can stop a locally ringing alarm. Use POST /api/devices/:deviceId/alarms/:alarmId/dismiss to stop one alarm on one remote device without dismissing it from history or stopping other receivers.

FieldNotes
platformandroid, macos, future ios, or another client type.
priorityLower numbers are intended to ring earlier. Defaults: macOS 10, iOS 20, Android 30.
enabledDisabled devices stay registered but do not receive event deliveries.
lastSeenAtServer timestamp for the receiver's last registration or long-poll sync. Native clients show it as last sync time.
ringingAlarmPresent when that receiver reported it is ringing. Includes alarmId, title, severity, and timestamps so another device can stop that exact receiver.
deliveryModeAccount setting. all rings every enabled device at once; ordered rings by priority and adds the next device after escalationIntervalSeconds.
capabilitiesClient-reported support such as longPoll, intrusiveAlarm, fullScreen, localSound, deliveryControls, aiConversationResume, aiConversationResumeKinds, and launchAtLogin.
curl -fsS https://pager.quave.ai/api/devices \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY"

curl -fsS -X PATCH https://pager.quave.ai/api/devices/<device-id> \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "priority": 10, "enabled": true }'

curl -fsS -X DELETE https://pager.quave.ai/api/devices/<device-id> \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY"

curl -fsS -X POST https://pager.quave.ai/api/devices/<device-id>/alarms/<alarm-id>/dismiss \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY"

9. List Alarm History

Use GET /api/alarms with the same bearer token to inspect scheduled and past alarms before creating a duplicate. Regular reads hide alarms with removedAt; use ?includeRemoved=true only when auditing logical deletes. Production state is durable in MongoDB.

curl -fsS https://pager.quave.ai/api/alarms \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY"

The native Android and macOS apps cache this list locally and schedule synced future alarms as a best-effort offline fallback. Online delivery is authoritative for ordered escalation windows.

10. Manage Existing Alarms

The package CLI supports the common management operations directly. Prefer it for agent work; the HTTP endpoints below are the underlying contract. Removed alarms stay in MongoDB with removedAt, but regular list, update, and delivery paths ignore them.

npx -y github:quavedev/pager-agent list
npx -y github:quavedev/pager-agent edit <alarm-id> --scheduled-at "2026-06-13 16:19:00" --time-zone "America/Campo_Grande" --status pending
npx -y github:quavedev/pager-agent remove <alarm-id>
npx -y github:quavedev/pager-agent snooze <alarm-id> --delay-seconds 600
ActionEndpointNotes
EditPATCH /api/alarms/:id or POST /api/alarms/:idEdit title, body, severity, link, aiConversationResume, deviceId, scheduledAt, timeZone, delaySeconds, ttlSeconds, expiresAt, and status. Use clearAiConversationResume: true to remove resume metadata. Use status: "pending" when rescheduling a past alarm.
SnoozePOST /api/alarms/:id/snoozeSend delaySeconds or a concrete scheduledAt plus timeZone. Sets status: "snoozed".
DismissPOST /api/alarms/:id/dismissKeeps the alarm in history and records dismissedAt.
CancelPOST /api/alarms/:id/cancelKeeps the alarm in history and records canceledAt.
RemoveDELETE /api/alarms/:id or POST /api/alarms/:id/removeLogical delete through removedAt.
curl -fsS -X PATCH https://pager.quave.ai/api/alarms/<alarm-id> \
  -H "Authorization: Bearer $QUAVE_PAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Look at Codex: updated schedule.",
    "scheduledAt": "YYYY-MM-DDT09:30:00",
    "timeZone": "America/Campo_Grande",
    "status": "pending"
  }'