Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ptshen/timeful-plus/llms.txt

Use this file to discover all available pages before exploring further.

Timeful uses session-based authentication. When a user signs in, the server sets an encrypted cookie named session. Every subsequent request from the same browser or HTTP client automatically carries that cookie, allowing the server to identify the caller without requiring a token header. Routes that require a valid session are wrapped with middleware.AuthRequired(). If the cookie is absent or the referenced user no longer exists in MongoDB, the middleware aborts the request with a 401 Unauthorized response:
{ "error": "not-signed-in" }

Anonymous Use

Several endpoints work without signing in:
  • GET /api/events/:eventId — view any event
  • POST /api/events — create an event as a guest
  • POST /api/events/:eventId/response — submit availability as a guest (pass "guest": true)
  • DELETE /api/events/:eventId/response — delete a guest response
  • POST /api/events/:eventId/rename-user — rename a guest respondent
  • POST /api/events/:eventId/responded — mark a remindee as having responded

Sign-In Flow (Web)

The web client uses Google OAuth’s server-side authorization code flow.
1

Initiate Google OAuth

The frontend redirects the user to Google’s authorization endpoint. Google returns an authorization code and scope string to your redirect URI.
2

POST /api/auth/sign-in

Exchange the code for a session by posting the authorization code to the server. The server calls Google’s token endpoint, creates or updates the user record in MongoDB, and sets the session cookie in the response.Request body:
FieldTypeRequiredDescription
codestringGoogle OAuth authorization code
scopestringOAuth scope string returned by Google
calendarTypestring"google" or "outlook"
timezoneOffsetintegerCaller’s UTC offset in minutes
eventsToLinkstring[]Event IDs to associate with the new user
Response 200 OK: Returns the signed-in User object.
3

Include the Cookie

All subsequent requests automatically include the session cookie (browsers handle this natively; CLI tools need --cookie-jar / -c flags).

Sign-In Flow (Mobile)

Mobile apps obtain OAuth tokens directly (e.g. via the Google Sign-In SDK) and then post those tokens to:
POST /api/auth/sign-in-mobile
Request body:
FieldTypeRequiredDescription
accessTokenstringOAuth 2.0 access token
scopestringOAuth scope string
idTokenstringJWT ID token containing user profile claims
expiresInintSeconds until the access token expires
refreshTokenstringOAuth 2.0 refresh token
tokenOriginstringPlatform: "ios" or "android"
calendarTypestring"google" or "outlook"
timezoneOffsetintCaller’s UTC offset in minutes
Response 200 OK: Returns an empty JSON object {}. The session cookie is set on the response.

CalendarType Values

Defined in models/calendar.go:
JSON valueMeaning
"google"Google Calendar (OAuth 2.0)
"outlook"Microsoft Outlook (OAuth 2.0)
"apple"Apple Calendar (app password)

TokenOrigin Values

Defined in models/user.go:
JSON valueMeaning
"web"Browser
"ios"iOS app
"android"Android app

Sign-Out

POST /api/auth/sign-out
Clears the userId key from the session. No request body required. Response 200 OK: Returns {}.

Auth Status

GET /api/auth/status
This endpoint is protected by middleware.AuthRequired(). It returns 401 if the caller is not signed in.
Returns {} with a 200 status when the session is valid. Use this to check whether a session cookie is still active. Example:
curl -s -c cookies.txt http://localhost:3002/api/auth/status
If the session is valid, the response is 200 {}. If not, you receive:
{ "error": "not-signed-in" }

Example: Check Auth Status

# After signing in (session cookie stored in cookies.txt)
curl -s \
  -b cookies.txt \
  http://localhost:3002/api/auth/status

Protecting Custom Routes

The middleware.AuthRequired() function is a standard Gin middleware. When it succeeds it stores the authenticated *models.User under the "authUser" context key, accessible in handlers via:
userInterface, _ := c.Get("authUser")
user := userInterface.(*models.User)

Build docs developers (and LLMs) love