Open Morse

Reference

Billing

7 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.

Begin buying a plan. Returns the Stripe Checkout URL to send the browser to.

POST/billing/checkout

Nothing is granted here: the session only starts the payment, and the plan follows from the webhook once Stripe says it was paid.

POST/billing/checkout

curl -X POST "$MORSE/billing/checkout" \
  -H "Authorization: Bearer $MORSE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "lookup_key": "…" }'
200
{
  "url": "https://onmorse.com/priya"
}

The launch offer: thirty days of Scale, free, one to a customer.

POST/billing/free-month

No Stripe and no card. It was £1.99 through Checkout; now nothing is charged, so there is no session to send them to and the month starts here rather than when a webhook lands. passes already means "one per person, ever" and already expires itself, so day 31 needs no sweeper: plan_for stops counting a pass the moment expires_at passes.

POST/billing/free-month

curl -X POST "$MORSE/billing/free-month" \
  -H "Authorization: Bearer $MORSE_TOKEN"

What you are on: your plan, and every source of it — subscription, launch pass, and a comp Morse gave you.

GET/billing/me

Read from our projection rather than from Stripe, so rendering the settings page does not depend on Stripe being up. Where the two disagree Stripe wins and the webhook rebuilds the row (F1).

GET/billing/me

curl "$MORSE/billing/me" \
  -H "Authorization: Bearer $MORSE_TOKEN"
200
{
  "grant": null,
  "pass": null,
  "pass_used": true,
  "plan": "…",
  "subscription": null
}

A free account's 25% off for its first months, while its 48 hours last.

GET/billing/offer

Asking opens the window the first time. Null when there is none for this account.

GET/billing/offer

curl "$MORSE/billing/offer" \
  -H "Authorization: Bearer $MORSE_TOKEN"

Close the offer card.

POST/billing/offer/dismiss

The offer itself stands until it ends.

POST/billing/offer/dismiss

curl -X POST "$MORSE/billing/offer/dismiss" \
  -H "Authorization: Bearer $MORSE_TOKEN"

Manage the subscription: cards, invoices, cancelling. Returns a Stripe URL.

POST/billing/portal

One endpoint for all of it because Stripe hosts the whole of that UI, and rebuilding any of it here would be a second place that has to stay correct about what someone is paying.

POST/billing/portal

curl -X POST "$MORSE/billing/portal" \
  -H "Authorization: Bearer $MORSE_TOKEN"
200
{
  "url": "https://onmorse.com/priya"
}

What you have used this month, and what your plan allows.

GET/billing/usage

**Alone among these routes it does not need Stripe.** What somebody has used is true whether or not this server can take money, and the plan comes from billing.plan_for, which reads our own rows. Holding it to _require_stripe would make a fresh clone unable to say "3 of 10" about meetings it had itself recorded. It reports and refuses nothing. Enforcement is plan 026, and is blocked on the open questions in docs/PRICING.md §6.

GET/billing/usage

curl "$MORSE/billing/usage" \
  -H "Authorization: Bearer $MORSE_TOKEN"
200
{
  "context_months": 1,
  "meetings_limit": 20,
  "meetings_used": 1,
  "minutes_limit": 30,
  "period_end": "2026-10-02T10:30:00+05:30",
  "period_start": "2026-10-02T10:30:00+05:30",
  "plan": "…"
}