Open Morse

Reference

Calendar

8 routes, generated from Morse’s own OpenAPI document. Every path below hangs off the base URL, and every one needs the bearer header.

The examples are built from each route’s schema, so the shapes and types are exactly what the API declares. The values are illustrative, and no one has run them.

Whether the time in the Schedule dialog suits everyone, and if not, what does on the same day (plan 034, the dialog's design C).

POST/calendar/check

One freeBusy for the whole local day, so the alternatives cost nothing extra.

POST/calendar/check

curl -X POST "$MORSE/calendar/check" \
  -H "Authorization: Bearer $MORSE_TOKEN" \
  -H "x-timezone: Asia/Kolkata" \
  -H "Content-Type: application/json" \
  -d '{ "emails": [ "priya@neuralarc.ai" ], "minutes": 30, "start": "2026-10-02T10:30:00+05:30" }'
200
{
  "assumed_zone": [
    "…"
  ],
  "busy": [
    "…"
  ],
  "guests": [
    "…"
  ],
  "nearby": [
    {
      "starts_at": "2026-10-02T10:30:00+05:30",
      "stretched": [
        {
          "email": "priya@neuralarc.ai",
          "local_time": "…",
          "zone": "…"
        }
      ]
    }
  ],
  "status": "ok",
  "stretched": [
    {
      "email": "priya@neuralarc.ai",
      "local_time": "…",
      "zone": "…"
    }
  ],
  "unchecked": [
    "…"
  ],
  "you_busy": true
}

access_type=offline is what earns a refresh token at all, and prompt=consent is what earns one *again* on a re-connect — without it Google returns an access token and no refresh token for a user who has consented before, which works for an hour and then fails forever.

GET/calendar/connect

login_hint pre-selects the right account, so someone with a personal Gmail open in the same browser is not walked into the D13 mismatch. Signed in by the cookie on the web, by a handoff from the iOS app. A handoff that fails does not fall back to the cookie: whoever sent one meant it.

GET/calendar/connect

curl "$MORSE/calendar/connect" \
  -H "Authorization: Bearer $MORSE_TOKEN"

Where Google sends a browser back after connecting a calendar.

GET/calendar/connect/callback

Not for scripts.

GET/calendar/connect/callback

curl "$MORSE/calendar/connect/callback" \
  -H "Authorization: Bearer $MORSE_TOKEN"

For the iOS app, whose browser sheet does not carry its cookie: it opens /connect?handoff=…&from=ios instead.

POST/calendar/connect/handoff

See security.mint_calendar_handoff.

POST/calendar/connect/handoff

curl -X POST "$MORSE/calendar/connect/handoff" \
  -H "Authorization: Bearer $MORSE_TOKEN"
200
{
  "expires_in": 1,
  "handoff": "…"
}

Never 404s and never 503s: "no calendar" is a normal state, and the page that asks has to render for someone who has never connected.

GET/calendar/connection

GET/calendar/connection

curl "$MORSE/calendar/connection" \
  -H "Authorization: Bearer $MORSE_TOKEN"
200
{
  "available": true,
  "connected": true,
  "connected_at": "2026-10-02T10:30:00+05:30",
  "email": "priya@neuralarc.ai",
  "status": "…"
}

Revoke at Google, then delete. Deleting alone would leave a live grant in the user's Google account with nothing in Morse to show for it, which is the one outcome a Disconnect button must not produce.

DELETE/calendar/connection

Events already created stay on everyone's calendars — they are other people's entries now, and silently clearing three colleagues' diaries is not something this button should do (plan 002 D14).

DELETE/calendar/connection

curl -X DELETE "$MORSE/calendar/connection" \
  -H "Authorization: Bearer $MORSE_TOKEN"

Everything on this person's calendar for a window: their meetings, and the rest of their Google Calendar with the Morse meetings taken out.

GET/calendar/events

Read through to Google on every call — no events table, no cache (D6). A cached copy that can be stale is worse than a fetch that can be slow for a page a human is looking at, and at tens of users one call per render is nothing against a million-queries-a-day quota. google=false reads meetings only, for a caller that draws no Google half — the page's side panel, looking at the weeks ahead. Google being unreachable is a caveat, not a failure: the Morse half still renders and the page says the other half is missing.

GET/calendar/events

curl "$MORSE/calendar/events?start=2026-10-02T10%3A30%3A00%2B05%3A30&end=2026-10-02T10%3A30%3A00%2B05%3A30" \
  -H "Authorization: Bearer $MORSE_TOKEN"
200
{
  "configured": true,
  "connected": true,
  "google": [
    {
      "all_day": true,
      "attendee_count": 3,
      "busy": true,
      "ends_at": "2026-10-02T10:30:00+05:30",
      "html_link": "https://onmorse.com/priya",
      "id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
      "organizer_name": "Priya Shah",
      "orphaned": true,
      "starts_at": "2026-10-02T10:30:00+05:30",
      "title": "Pricing review"
    }
  ],
  "google_available": true,
  "google_error": "…",
  "meetings": [
    {
      "archived": true,
      "at_risk": true,
      "attendee_count": 3,
      "attendees": [
        {
          "id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
          "name": "Priya Shah"
        }
      ],
      "booked": true,
      "booked_by_me": true,
      "booked_timezone": "Asia/Kolkata",
      "booking_note": "…",
      "calendar_sync_status": "synced",
      "code": "4KJ9P2",
      "copilot_enabled": true,
      "created_at": "2026-10-02T10:30:00+05:30",
      "duration_minutes": 30,
      "ended_at": "2026-10-02T10:30:00+05:30",
      "generated_title": "…",
      "has_whiteboard": true,
      "host_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
      "host_name": "Priya Shah",
      "host_title": "…",
      "id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
      "in_room": true,
      "internal": true,
      "invite_counts": 3,
      "invitee_names": [
        "Priya Shah"
      ],
      "invitees": [
        {
          "id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
          "name": "Priya Shah"
        }
      ],
      "is_host": true,
      "locked": true,
      "my_proposed_start": "2026-10-02T10:30:00+05:30",
      "my_response": "…",
      "notes_ready": true,
      "notes_viewed": true,
      "notes_writing": true,
      "on_calendar": true,
      "open_suggestions": 1,
      "record_access": "host",
      "recording_available": true,
      "recording_enabled": true,
      "scheduled_at": "2026-10-02T10:30:00+05:30",
      "started_at": "2026-10-02T10:30:00+05:30",
      "status": "…",
      "summary_template": "…",
      "title": "Pricing review",
      "transcription_enabled": true,
      "whiteboard_open": true
    }
  ],
  "needs_reconnect": true
}

Suggested times for the Schedule dialog (plan 034). Nothing is written.

POST/calendar/suggestions

Asks Google only what the host could ask in Google Calendar themselves: freeBusy with their own grant, under each colleague's sharing settings.

POST/calendar/suggestions

curl -X POST "$MORSE/calendar/suggestions" \
  -H "Authorization: Bearer $MORSE_TOKEN" \
  -H "x-timezone: Asia/Kolkata" \
  -H "Content-Type: application/json" \
  -d '{ "emails": [ "priya@neuralarc.ai" ], "minutes": 30 }'
200
{
  "assumed_zone": [
    "…"
  ],
  "guests": [
    "…"
  ],
  "slots": [
    {
      "starts_at": "2026-10-02T10:30:00+05:30",
      "stretched": [
        {
          "email": "priya@neuralarc.ai",
          "local_time": "…",
          "zone": "…"
        }
      ]
    }
  ],
  "status": "ok",
  "unchecked": [
    "…"
  ]
}