---
title: "Replace hand-marked slots inside a window (live for a proven address, otherwise confirmed by email)"
method: POST
path: "/api/manual-availability"
---

# Replace hand-marked slots inside a window (live for a proven address, otherwise confirmed by email)

`POST /api/manual-availability`

## Request

- Base URL: `https://whenmeet.me`
- URL: `https://whenmeet.me/api/manual-availability`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `__Host-session`
  - none

The manual fallback for people who do not publish an iCloud calendar, prefer not to connect a calendar, use another unsupported calendar, or have no calendar; the heat-map labels it source "manual". Goes LIVE FOR EVERYONE (200) when the caller is signed in and the email is one of their own addresses (account email, a connected Google / Microsoft calendar, a team address they joined under), or when k is the owner proof returned by Confirm. With a host-issued ask-link k (POST /api/ask-links) it goes live ONLY FOR THAT HOST (200 with scope: "host" and hostName): their picker and meeting heat-maps see it, nobody else does, until the person shares it with everyone (POST /api/manual-availability/share). Anyone else gets 202 { ok, pending: true, email }: nothing is published, and that address gets a "Confirm your free times" email whose link (GET /api/manual-availability/confirm) opens /free with a one-click Confirm (POST /api/manual-availability/confirm) that publishes the save. Pending saves expire after 7 days (≤ 5 per address); a save that is live for everyone drops the address's older pending ones (a host-scoped save keeps them). Confirmation emails per 24 h: 3 per sender per address, 10 per address, 20 per signed-in sender (session / PAT) and 10 per anonymous IP per hour (claimed atomically before anything is stored; a refused mail costs nothing). Anonymous callers need a Turnstile token (also with k), and may not paint an address that has a connected account (409). Rate-limited per email (30 saves/h); a host-scoped save counts against that host's own budget for the address, so nobody's ask-link saves use up the owner's.

## Request body

- object
  - `email` string, email, required
  - `windowFrom` integer, required
  - `windowTo` integer, required
  - `freeSlots` Interval[], required
    - `start` integer, required
    - `end` integer, required
  - `busySlots` Interval[]: Optional extra busy blocks.
    - `start` integer, required
    - `end` integer, required
  - `k` string: Signature from a /free?email=…&k=… link, `<issuerId>.<22-char sig>`. A host-issued k (POST /api/ask-links) makes the save live for that host only; the owner proof from Confirm (empty issuer, `.<sig>`) makes it live for everyone. An M7 22-char k without an issuer proves nothing (→ 202 pending).
  - `turnstileToken` string: Required for anonymous callers when Turnstile is configured.

## Response `200`

Saved live: { ok, email, saved, free, busy }, plus scope: "host" and hostName when it is live only for the host whose ask-link k it carried.

- object
  - `ok` boolean
  - `email` string
  - `saved` integer
  - `free` integer
  - `busy` integer
  - `scope` 'host': Present only for a host-scoped save.
  - `hostName` string, nullable: That host's display name or first name ("Shared with <hostName>."); never an email.

## Other responses

- `202`: Pending until the address owner confirms by email: { ok, pending: true, email }.
- `400`: bad_request | invalid_email | bad_window | window_out_of_range | too_many_slots | slots_out_of_window.
- `403`: turnstile_failed.
- `409`: account_exists (anonymous caller, the address has a connected calendar — sign in instead).
- `429`: rate_limited (30 saves/h per email — per email and host for a host-scoped save — or a confirmation-email limit; nothing stored).
- `502`: email_failed (the confirmation email could not be sent; nothing kept).

---

[API](https://skmtc.dev/whenmeet/apis/whenmeet-me-api.md) · [All operations](https://skmtc.dev/whenmeet/apis/whenmeet-me-api/llms.txt) · [OpenAPI document](https://skmtc.dev/whenmeet/apis/whenmeet-me-api/revisions/202b80022215?raw)
