Reference
Admin
30 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.
Who shared what with whom, who asked, what left by email, and what admins read and did — newest first, read-only (plan 015 D4).
/admin/auditGET/admin/audit
curl "$MORSE/admin/audit" \
-H "Authorization: Bearer $MORSE_TOKEN"[
{
"action": "…",
"actor_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"actor_name": "Priya Shah",
"at": "2026-10-02T10:30:00+05:30",
"detail": {},
"email": "priya@neuralarc.ai",
"key": "…",
"kind": "…",
"meeting_code": "…",
"meeting_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"meeting_title": "…",
"user_email": "priya@neuralarc.ai",
"user_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"user_name": "Priya Shah"
}
]Comp every account that has none, so enforcement day cuts off nobody who was already here (D4). Admins only, and one logged comp each (G4).
/admin/billing/grandfatherSafe to run twice (G5): it never overwrites a comp, and it leaves alone any account an admin has already decided about — including one whose comp was deliberately revoked.
POST/admin/billing/grandfather
curl -X POST "$MORSE/admin/billing/grandfather" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "plan": "…", "reason": "…" }'{
"skipped": 1,
"written": 1
}Every broadcast, newest first.
/admin/broadcastsGET/admin/broadcasts
curl "$MORSE/admin/broadcasts" \
-H "Authorization: Bearer $MORSE_TOKEN"[
{
"audience": "outside",
"body": "Annual plans are billed up front.",
"created_at": "2026-10-02T10:30:00+05:30",
"created_by": "…",
"created_by_name": "Priya Shah",
"failed": 1,
"finished_at": "2026-10-02T10:30:00+05:30",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"recipients": 1,
"sent": 1,
"started_at": "2026-10-02T10:30:00+05:30",
"status": "draft",
"subject": "…",
"tested_at": "2026-10-02T10:30:00+05:30"
}
]A draft.
/admin/broadcastsNothing is sent and no audience is resolved until it is started.
POST/admin/broadcasts
curl -X POST "$MORSE/admin/broadcasts" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "audience": "outside", "body": "Annual plans are billed up front.", "subject": "…" }'{
"audience": "outside",
"body": "Annual plans are billed up front.",
"created_at": "2026-10-02T10:30:00+05:30",
"created_by": "…",
"created_by_name": "Priya Shah",
"failed": 1,
"finished_at": "2026-10-02T10:30:00+05:30",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"recipients": 1,
"sent": 1,
"started_at": "2026-10-02T10:30:00+05:30",
"status": "draft",
"subject": "…",
"tested_at": "2026-10-02T10:30:00+05:30"
}Who is reachable right now, by audience — disabled accounts and people who have unsubscribed are already out of these numbers.
/admin/broadcasts/audiencesGET/admin/broadcasts/audiences
curl "$MORSE/admin/broadcasts/audiences" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"everyone": 1,
"internal": 1,
"outside": 1
}Render the draft as typed, without saving it or sending anything.
/admin/broadcasts/previewDeliberately email.broadcast_content and nothing else — the same call the
sender makes for every recipient. A preview rendered by a second code path
is a preview that can quietly stop agreeing with the email, and the admin
would only find out from the people who received it.
It renders as the acting admin: their first name in the greeting, their own
unsubscribe token in the footer. A stub there would be the one part of the
page that is not what goes out, and it is the part people ask about.
POST/admin/broadcasts/preview
curl -X POST "$MORSE/admin/broadcasts/preview" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body": "Annual plans are billed up front.", "subject": "…" }'{
"html": "…",
"subject": "…",
"text": "Annual plans are billed up front."
}One broadcast, with how far a send has got: how many were queued, sent and failed.
/admin/broadcasts/{broadcast_id}GET/admin/broadcasts/{broadcast_id}
curl "$MORSE/admin/broadcasts/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"audience": "outside",
"body": "Annual plans are billed up front.",
"created_at": "2026-10-02T10:30:00+05:30",
"created_by": "…",
"created_by_name": "Priya Shah",
"failed": 1,
"finished_at": "2026-10-02T10:30:00+05:30",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"recipients": 1,
"sent": 1,
"started_at": "2026-10-02T10:30:00+05:30",
"status": "draft",
"subject": "…",
"tested_at": "2026-10-02T10:30:00+05:30"
}Change a draft.
/admin/broadcasts/{broadcast_id}A broadcast that has started is not editable: it is the record of what went out.
PUT/admin/broadcasts/{broadcast_id}
curl -X PUT "$MORSE/admin/broadcasts/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "audience": "outside", "body": "Annual plans are billed up front.", "subject": "…" }'{
"audience": "outside",
"body": "Annual plans are billed up front.",
"created_at": "2026-10-02T10:30:00+05:30",
"created_by": "…",
"created_by_name": "Priya Shah",
"failed": 1,
"finished_at": "2026-10-02T10:30:00+05:30",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"recipients": 1,
"sent": 1,
"started_at": "2026-10-02T10:30:00+05:30",
"status": "draft",
"subject": "…",
"tested_at": "2026-10-02T10:30:00+05:30"
}Throw a draft away.
/admin/broadcasts/{broadcast_id}A broadcast that has been sent stays: it is the record of what went out, and a record that can be deleted is not one.
DELETE/admin/broadcasts/{broadcast_id}
curl -X DELETE "$MORSE/admin/broadcasts/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60" \
-H "Authorization: Bearer $MORSE_TOKEN"Who it went to and what happened — failures first.
/admin/broadcasts/{broadcast_id}/recipientsGET/admin/broadcasts/{broadcast_id}/recipients
curl "$MORSE/admin/broadcasts/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/recipients" \
-H "Authorization: Bearer $MORSE_TOKEN"[
{
"email": "priya@neuralarc.ai",
"error": "…",
"name": "Priya Shah",
"sent_at": "2026-10-02T10:30:00+05:30",
"status": "pending"
}
]Resolve the audience, queue everyone, and start sending.
/admin/broadcasts/{broadcast_id}/sendCannot be undone, and cannot be done twice (plan 040 R7).
POST/admin/broadcasts/{broadcast_id}/send
curl -X POST "$MORSE/admin/broadcasts/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/send" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"audience": "outside",
"body": "Annual plans are billed up front.",
"created_at": "2026-10-02T10:30:00+05:30",
"created_by": "…",
"created_by_name": "Priya Shah",
"failed": 1,
"finished_at": "2026-10-02T10:30:00+05:30",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"recipients": 1,
"sent": 1,
"started_at": "2026-10-02T10:30:00+05:30",
"status": "draft",
"subject": "…",
"tested_at": "2026-10-02T10:30:00+05:30"
}Send it to the acting admin, and to nobody else (plan 040 R8).
/admin/broadcasts/{broadcast_id}/testPOST/admin/broadcasts/{broadcast_id}/test
curl -X POST "$MORSE/admin/broadcasts/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/test" \
-H "Authorization: Bearer $MORSE_TOKEN"Free a booking handle somebody used to have (0053).
/admin/handles/{handle}A retired handle is kept because links already sent still point at it, so releasing one is deliberately an admin act and not a self-service button: it hands the name to whoever asks next, and every one of those old links then reaches them instead. The case it exists for is somebody leaving. Only a retired handle. A handle somebody is using now is theirs, and nothing here takes it off them.
DELETE/admin/handles/{handle}
curl -X DELETE "$MORSE/admin/handles/…" \
-H "Authorization: Bearer $MORSE_TOKEN"Newest first, a page at a time (before is the last row's sort_at).
/admin/meetingsstatus is one of a meeting's statuses among those not deleted, or
deleted; since and until bound when it started, is booked for, or was
made. The client sends the bounds, since "today" is the admin's own day.
GET/admin/meetings
curl "$MORSE/admin/meetings" \
-H "Authorization: Bearer $MORSE_TOKEN"[
{
"attendees": 1,
"code": "4KJ9P2",
"created_at": "2026-10-02T10:30:00+05:30",
"deleted_at": "2026-10-02T10:30:00+05:30",
"ended_at": "2026-10-02T10:30:00+05:30",
"host_disabled": true,
"host_email": "priya@neuralarc.ai",
"host_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"host_name": "Priya Shah",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"scheduled_at": "2026-10-02T10:30:00+05:30",
"sort_at": "2026-10-02T10:30:00+05:30",
"started_at": "2026-10-02T10:30:00+05:30",
"status": "…",
"title": "Pricing review",
"with_access": 1
}
]The figures atop the Meetings list, over every meeting rather than a page.
/admin/meetings/countsGET/admin/meetings/counts
curl "$MORSE/admin/meetings/counts" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"ended_week": 1,
"live": 1,
"upcoming": 1
}One meeting in full for an admin, with each time an admin opened it and why.
/admin/meetings/{meeting_id}Admins only.
GET/admin/meetings/{meeting_id}
curl "$MORSE/admin/meetings/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"attendees": 1,
"code": "4KJ9P2",
"created_at": "2026-10-02T10:30:00+05:30",
"deleted_at": "2026-10-02T10:30:00+05:30",
"ended_at": "2026-10-02T10:30:00+05:30",
"host_disabled": true,
"host_email": "priya@neuralarc.ai",
"host_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"host_name": "Priya Shah",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"open_until": "2026-10-02T10:30:00+05:30",
"opens": [
{
"admin_email": "priya@neuralarc.ai",
"admin_name": "Priya Shah",
"expires_at": "2026-10-02T10:30:00+05:30",
"opened_at": "2026-10-02T10:30:00+05:30",
"reason": "…"
}
],
"scheduled_at": "2026-10-02T10:30:00+05:30",
"sort_at": "2026-10-02T10:30:00+05:30",
"started_at": "2026-10-02T10:30:00+05:30",
"status": "…",
"title": "Pricing review",
"with_access": 1
}Open a meeting to read, with a reason, for admin.READ_FOR.
/admin/meetings/{meeting_id}/openThe host sees every open, and is emailed the first time each admin opens it each day.
POST/admin/meetings/{meeting_id}/open
curl -X POST "$MORSE/admin/meetings/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/open" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "x-timezone: Asia/Kolkata" \
-H "Content-Type: application/json" \
-d '{ "reason": "…" }'Make another colleague the host of a finished meeting.
/admin/meetings/{meeting_id}/transferAdmins only.
POST/admin/meetings/{meeting_id}/transfer
curl -X POST "$MORSE/admin/meetings/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/transfer" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "to": "…" }'{
"attendees": 1,
"code": "4KJ9P2",
"created_at": "2026-10-02T10:30:00+05:30",
"deleted_at": "2026-10-02T10:30:00+05:30",
"ended_at": "2026-10-02T10:30:00+05:30",
"host_disabled": true,
"host_email": "priya@neuralarc.ai",
"host_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"host_name": "Priya Shah",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"scheduled_at": "2026-10-02T10:30:00+05:30",
"sort_at": "2026-10-02T10:30:00+05:30",
"started_at": "2026-10-02T10:30:00+05:30",
"status": "…",
"title": "Pricing review",
"with_access": 1
}Every account, narrowed by q (name, email or role), at most 500.
/admin/peopleAdmins only.
GET/admin/people
curl "$MORSE/admin/people" \
-H "Authorization: Bearer $MORSE_TOKEN"[
{
"admin": "…",
"created_at": "2026-10-02T10:30:00+05:30",
"disabled": true,
"email": "priya@neuralarc.ai",
"hosted": 1,
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"last_seen_at": "2026-10-02T10:30:00+05:30",
"name": "Priya Shah",
"retired_handles": [
"…"
],
"title": "Pricing review",
"tokens": "mp_YOUR_MORSE_TOKEN"
}
]Rename, retitle, disable or enable, make or unmake an admin — each change logged. Nobody changes their own disabled or admin standing, and an admin named in ADMIN_EMAILS can't be disabled or demoted here (plan 015 R3).
/admin/people/{person_id}Allowing a booking page used to be here too. It is not a grant any more:
everyone may have one (auth.may_book), so there is nothing for an admin to
hand out. booking_on and booking_off stay permitted in admin_events
for the history already written, and nothing produces them now.
PATCH/admin/people/{person_id}
curl -X PATCH "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "disabled": true, "is_admin": true, "name": "Priya Shah", "title": "Pricing review" }'{
"admin": "…",
"created_at": "2026-10-02T10:30:00+05:30",
"disabled": true,
"email": "priya@neuralarc.ai",
"hosted": 1,
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"last_seen_at": "2026-10-02T10:30:00+05:30",
"name": "Priya Shah",
"retired_handles": [
"…"
],
"title": "Pricing review",
"tokens": "mp_YOUR_MORSE_TOKEN"
}Their whole billing state: the resolved plan and what answers for it, the subscription, the launch pass, the comp, this month's use, and what admins did to any of it (D3). Admins only.
/admin/people/{person_id}/billingNot itself logged. It changes nothing, and an audit filled with page views
is one nobody reads — what admins *did* is what events carries.
GET/admin/people/{person_id}/billing
curl "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/billing" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"events": [
{
"action": "…",
"actor_email": "priya@neuralarc.ai",
"actor_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"actor_name": "Priya Shah",
"at": "2026-10-02T10:30:00+05:30",
"detail": {}
}
],
"grant": null,
"pass": null,
"pass_used": true,
"plan": "…",
"source": "subscription",
"subscription": null,
"usage": {
"meetings_limit": 20,
"meetings_used": 1,
"period_end": "2026-10-02T10:30:00+05:30",
"period_start": "2026-10-02T10:30:00+05:30"
}
}Comp this account: paid access with no money moving, replacing any comp it had. Nothing is asked of Stripe (G2). Admins only, and logged (G4).
/admin/people/{person_id}/grantAn admin may comp their own account (G6). A block would be theatre — an admin can comp a colleague who comps them back — and this is logged like anything else, which is the actual check.
PUT/admin/people/{person_id}/grant
curl -X PUT "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/grant" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "plan": "…", "reason": "…" }'{
"created_at": "2026-10-02T10:30:00+05:30",
"expires_at": "2026-10-02T10:30:00+05:30",
"granted_by_email": "priya@neuralarc.ai",
"granted_by_name": "Priya Shah",
"plan": "…",
"reason": "…",
"updated_at": "2026-10-02T10:30:00+05:30"
}Take the comp away (D5).
/admin/people/{person_id}/grantThey fall back to whatever they actually pay for, which may be nothing. Admins only, and logged (G4).
DELETE/admin/people/{person_id}/grant
curl -X DELETE "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/grant" \
-H "Authorization: Bearer $MORSE_TOKEN"Move a live subscription onto another price — monthly ↔ yearly, or a different plan. Stripe prorates it. Admins only, and logged (G4).
/admin/people/{person_id}/subscription202 and not 200 because nothing here has changed yet: Morse asks Stripe and the webhook writes the projection (G3). 409 if there is no live subscription — a comp is how somebody gets a plan without paying.
POST/admin/people/{person_id}/subscription
curl -X POST "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/subscription" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "lookup_key": "…" }'{
"asked": "…",
"subscription_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60"
}End a live subscription when its period ends (D5). Admins only, logged.
/admin/people/{person_id}/subscriptionNever immediately: they paid for the period, and taking it back early is a refund, which is Stripe's and is not in this plan.
DELETE/admin/people/{person_id}/subscription
curl -X DELETE "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/subscription" \
-H "Authorization: Bearer $MORSE_TOKEN"{
"asked": "…",
"subscription_id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60"
}Every finished meeting this person hosts, to one active colleague.
/admin/people/{person_id}/transferPOST/admin/people/{person_id}/transfer
curl -X POST "$MORSE/admin/people/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60/transfer" \
-H "Authorization: Bearer $MORSE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "to": "…" }'Every figure on the admin overview, in one request.
/admin/statsDeliberately untyped at the edge: each section owns its own shape, and a response model here would be a twelfth place to update whenever one of them gains a figure. A section that fails answers null and the page draws an em dash for it, rather than the whole overview failing over one bad query.
GET/admin/stats
curl "$MORSE/admin/stats" \
-H "Authorization: Bearer $MORSE_TOKEN"Aggregate creation cohorts, never account identities.
/admin/stats/campaignsHalf-open UTC ranges.
GET/admin/stats/campaigns
curl "$MORSE/admin/stats/campaigns?start=2026-10-02T10%3A30%3A00%2B05%3A30&end=2026-10-02T10%3A30%3A00%2B05%3A30" \
-H "Authorization: Bearer $MORSE_TOKEN"Everyone's tokens, newest first, at most 500.
/admin/tokensAdmins only. person narrows
it to one owner; status=all includes expired and revoked ones.
GET/admin/tokens
curl "$MORSE/admin/tokens" \
-H "Authorization: Bearer $MORSE_TOKEN"[
{
"created_at": "2026-10-02T10:30:00+05:30",
"expires_at": "2026-10-02T10:30:00+05:30",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"last_four": "…",
"last_used_at": "2026-10-02T10:30:00+05:30",
"name": "Priya Shah",
"owner": {
"email": "priya@neuralarc.ai",
"id": "3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60",
"name": "Priya Shah"
},
"revoked_at": "2026-10-02T10:30:00+05:30",
"revoked_by_name": "Priya Shah",
"status": "active"
}
]Revoke anyone's token, from its next request.
/admin/tokens/{token_id}Admins only. Revoking someone else's is recorded in the audit (R12).
DELETE/admin/tokens/{token_id}
curl -X DELETE "$MORSE/admin/tokens/3f9c1a24-5e6f-4b31-9a77-1b2c3d4e5f60" \
-H "Authorization: Bearer $MORSE_TOKEN"