The Resident Council short-link tooling (stats, QR generation, and link creation) runs as Cloudflare Pages Functions, replacing three n8n workflows that shared one Short.io API key and one Notion Short.io DB. Shared plumbing lives in functions/_lib/shortio.ts (Notion pagination, Short.io API calls, QR URL builder) so each handler stays small.

Pieces

flowchart TD
  CRON["ihnyc-rc-cron-sync<br/>*/30"] --> STATS["/api/cron/sync-stats<br/>(X-Sync-Secret)"]
  ADMIN["admin / manual"] --> CREATE["/api/shortio/create<br/>(X-Sync-Secret)"]
  PUBLIC["link QR requests"] --> QR["/api/shortio/qr<br/>(public proxy)"]
  STATS --> LIB["_lib/shortio.ts"]
  CREATE --> LIB
  LIB --> SHORTIO["Short.io API"]
  LIB --> NOTION["Notion Short.io DB"]
  STATS --> R2["R2: stats.json (STATS_BUCKET)"]
  QR --> SHORTIO
EndpointReplaces (n8n)Does
POST /api/cron/sync-statsRC-ShortIO-GenerateStats-JSONQueries Notion for Active links, fetches 30-day Short.io click stats in parallel (Promise.allSettled — one bad link can’t abort the job), writes stats.json to R2. Cron */30 (n8n ran every minute, overkill for last-30 stats).
GET /api/shortio/qr?id=&name=RC-ShortIO-Proxy-QRGenPublic proxy to the Short.io QR API; returns PNG with a 1h cache
POST /api/shortio/createRC-ShortIO-Create (/webhook/qr-init)Finds Notion rows with an Original URL but no Short.io ID, creates the link, writes Short URL / ID / QR / Status / timestamps back to Notion

Auth

  • sync-stats and create require the X-Sync-Secret header.
  • qr is a public proxy (returns an image only).

Config / go-live

NameTypePurpose
SHORTIO_API_KEYsecret (sk_...)Short.io API access
X-Sync-SecretsecretGates sync-stats + create

Set SHORTIO_API_KEY via wrangler pages secret put before decommissioning n8n, and rotate the old exposed key at the same time. The */30 cron is added in the master cron Worker’s toml — redeploy that Worker to activate it.

  • n8n — the workflows this retires
  • ops — Pages Functions deploy notes