You are reading the documentation of Guestroll v0.1.1. The latest version is v0.5.0. Latest docs · What changed · Changelog
Skip to content

HTTP API ​

The routes the interface uses. They're stable within a major version, but they exist for the UI, not as a public integration API.

All mutating requests need a same-origin Origin header (browsers send it). Errors are JSON: { "error": "<code>", "details"?: { field: message } }.

CodeStatusMeaning
bad_request400Invalid input, see details
unauthorized401Not signed in as admin, or wrong password
invalid_code401Wrong event access code
forbidden403Cross-site request, or the guest hasn't joined the event
uploads_closed403Uploads are off or past their closing time
quota_reached403The guest reached the per-guest limit
not_found404Doesn't exist, or exists but isn't yours
too_large413Body above MAX_UPLOAD_MB
invalid_image415Not a supported image
rate_limited429Slow down; see Retry-After

Guest routes ​

Authenticated by the gr_guest cookie.

RouteBodyResponse
POST /api/e/:slug/joinnone{ ok }. Events without an access code only.
POST /api/e/:slug/unlock{ code }{ ok }
POST /api/e/:slug/guest{ name }{ name }. Stored in the cookie.
POST /api/e/:slug/photosmultipart, field photo201 { photo: PhotoDto }
GET /api/e/:slug/photos?before=<ms>{ photos: PhotoDto[], nextCursor }, the guest's own photos only
GET /api/e/:slug/logo?v=<n>The event logo (PNG), public with the slug
GET /api/media/:id?v=thumb|display|original[&download=1]The image, if the viewer may see it
ts
interface PhotoDto {
  id: string;
  width: number;
  height: number;
  guestName: string | null;
  status: "visible" | "pending" | "hidden";
  mine: boolean;
  downloads?: number; // admins only
  createdAt: number;  // epoch ms
}

Admin routes ​

Authenticated by the gr_admin cookie.

RouteBodyResponse
POST /api/admin/login{ password }{ ok }
POST /api/admin/logout{ ok }
POST /api/admin/password{ current, next }{ ok }
GET /api/admin/events{ events: EventSummary[] }
POST /api/admin/eventsevent fields, name required201 { event }
GET /api/admin/events/:id{ event }
PATCH /api/admin/events/:idany event fields{ event }
DELETE /api/admin/events/:id{ ok }, photos deleted from disk
POST /api/admin/events/:id/rotate{ event } with a new slug
POST /api/admin/events/:id/logomultipart, field logo{ event }
DELETE /api/admin/events/:id/logo{ event }
GET /api/admin/events/:id/qr?format=svg|png&size=512..4096&download=1The styled QR code
GET /api/admin/events/:id/photos?status=&before={ photos, nextCursor }
POST /api/admin/events/:id/photos{ action: "approve"|"hide"|"delete", ids }{ changed }
GET /api/admin/events/:id/archive[?all=1]Streamed ZIP; all=1 includes pending and hidden
GET /api/admin/stats[?eventId=]Totals, time series, top guests

Event fields: name, description, eventDate (YYYY-MM-DD), accentColor (#rrggbb), accessCode (string to set, null to remove), uploadsOpen, uploadsCloseAt (epoch ms or null), moderation (post|pre), captureMode (camera|picker|both), askGuestName, maxPhotosPerGuest, defaultLocale (en|fr|it|es|null), qrStyle (object, see src/lib/qr/style.ts).

Health ​

GET /api/health returns 200 {"status":"ok"}, or 503 when the database can't be read.

Released under the MIT License.