Skip to content

API Reference

Complete REST API documentation for Minispace.

Base URL

Each daycare has its own API, accessible via subdomain:

https://{daycare-slug}.minispace.app/api

Authentication

All protected endpoints require a JWT Bearer token in the Authorization header:

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     https://your-daycare.minispace.app/api/auth/me

Login Flow (2-step)

Step 1 — Credentials

POST /auth/login
{
  "email": "user@example.com",
  "password": "yourpassword"
}

Response (when 2FA is required):

{ "status": "2fa_required" }

Response (when trusted device cookie is present — 2FA skipped):

{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "user": { ... }
}

Step 2 — Verify 2FA code

POST /auth/verify-2fa
{
  "email": "user@example.com",
  "code": "123456"
}

Response:

{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "role": "educateur"
  },
  "garderie_name": "Garderie Les Étoiles"
}

Token Refresh

POST /auth/refresh
{ "refresh_token": "eyJ..." }

Returns a new access_token.

Logout

POST /auth/logout

Revokes the refresh token and clears the trusted-device cookie.

Password Reset

POST /auth/forgot-password
{ "email": "user@example.com" }

POST /auth/reset-password
{
  "token": "reset-token-from-email",
  "password": "newpassword"
}

User Roles

Role Description
admin_garderie Full admin access within their daycare
educateur Can manage journals, media, documents, and messaging
parent Read-only access to their children's data; can message staff

Endpoints

Authentication

Method Endpoint Description
POST /auth/login Step 1: email + password
POST /auth/verify-2fa Step 2: verify 6-digit code
POST /auth/refresh Refresh access token
POST /auth/logout Revoke session
GET /auth/me Get current user profile
POST /auth/change-password Change own password
POST /auth/update-email Change own email
POST /auth/invite Invite a user by email (admin)
GET /auth/invitations List pending invitations (admin)
DELETE /auth/invitations/{id} Delete an invitation (admin)
POST /auth/register Register from an invitation token
POST /auth/forgot-password Request password reset email
POST /auth/reset-password Reset password with token

Messages

Method Endpoint Description
GET /messages List messages (paginated)
POST /messages Send a message
POST /messages/send-to-parents Send message to parents with email notification
POST /messages/{id}/read Mark a message as read
GET /messages/conversations List all conversation threads
GET /messages/conversation/{user_id} Get individual conversation
GET /messages/thread/broadcast Get broadcast thread
GET /messages/thread/group/{group_id} Get group thread
GET /messages/thread/individual/{parent_id} Get individual thread

Send a message:

{
  "content": "Hello everyone!",
  "message_type": "broadcast"
}

message_type values: broadcast, group, individual

For group messages, add "group_id": "uuid". For individual messages, add "recipient_id": "uuid".

Children

Method Endpoint Description
GET /children List children (parents see only their own)
POST /children Create a child (admin)
PUT /children/{id} Update a child (admin)
DELETE /children/{id} Delete a child (admin)
GET /children/{id}/parents List a child's linked parents
POST /children/{id}/parents Link a parent to a child
DELETE /children/{id}/parents/{user_id} Unlink a parent

Groups

Method Endpoint Description
GET /groups List all groups
POST /groups Create a group (admin)
PUT /groups/{id} Update a group (admin)
DELETE /groups/{id} Delete a group (admin)
PUT /groups/{id}/children Set group members (admin)

Daily Journal

Method Endpoint Description
GET /journals Get a week's journal entries (?child_id=&week_start=YYYY-MM-DD)
PUT /journals Create or update a daily entry (staff only)
POST /journals/send-all-to-parents Email all children's journals
POST /journals/{child_id}/send-to-parents Email one child's journal

Journal entry fields:

Field Type Values
temperature enum ensoleille, nuageux, pluie, neige, orageux
menu string Free text
appetit enum comme_habitude, peu, beaucoup, refuse
humeur enum tres_bien, bien, difficile, pleurs
sommeil_minutes integer Duration in minutes
sante string Free text
medicaments string Free text
message_educatrice string Free text
observations string Free text

Media

Method Endpoint Description
POST /media Upload photo or video (multipart)
GET /media List media
PUT /media/{id} Update caption/visibility
DELETE /media/{id} Delete media
POST /media/bulk Bulk delete or reassign
GET /media/files/{path} Serve a media file

Visibility values: public, group, child, private

Documents

Method Endpoint Description
POST /documents Upload a document (multipart)
GET /documents List documents
PUT /documents/{id} Update document metadata
DELETE /documents/{id} Delete a document

Category values: formulaire, menu, politique, bulletin, autre

Users (Admin only)

Method Endpoint Description
GET /users List all users
POST /users Create a user directly
PUT /users/{id} Update role or status
DELETE /users/{id} Deactivate or delete a user
POST /users/{id}/reset-password Reset a user's password

Tenant

Method Endpoint Description
GET /tenant/info Get daycare name and logo URL
POST /tenant/logo Upload daycare logo (admin)
DELETE /tenant/logo Delete daycare logo (admin)

WebSocket

Real-time messages are delivered via WebSocket:

GET /ws?token=YOUR_ACCESS_TOKEN

Connect using your JWT access token as a query parameter. Messages are published to the socket when a new message, media, or document is created.

Rate Limiting

Action Limit
Login attempts 5 per 15 minutes per email
2FA verification 10 per 15 minutes per email
Forgot password 3 per 30 minutes per email

Error Handling

Errors follow a consistent format:

{
  "error": "unauthorized",
  "message": "Invalid or expired token",
  "status": 401
}

Common status codes:

Code Meaning
400 Bad request — check request body
401 Unauthorized — missing or invalid token
403 Forbidden — insufficient permissions
404 Not found
429 Too many requests — rate limited
500 Internal server error