Reference

API (preview)

Internal server functions used by the web app. A public API is on the roadmap.

Authentication

All authenticated calls carry a Supabase bearer token attached by the client middleware. Row-level security scopes every read and write to auth.uid().

Try it out

Run any endpoint live against your own account. Your session token is attached automatically — sign in first, otherwise every call returns unauthorized. Requests execute for real, so treat write and delete endpoints with care.

Try it out

Not signed in — calls will return 401

List your chat threads · /_serverFn/listChats

This endpoint takes no request body.

// Response will appear here

Chats

listChats() → Chat[]
createChat({ title }) → Chat
renameChat({ id, title }) → Chat
deleteChat({ id }) → { ok: true }

Messages

listMessages({ chatId }) → Message[]
sendMessage({ chatId, content }) → { reply: Message }

Profile

getProfile() → Profile
updateProfile({ display_name, avatar_url }) → Profile

Types

type Chat = {
  id: string;
  user_id: string;
  title: string;
  created_at: string; // ISO
  updated_at: string; // ISO
};

type Message = {
  id: string;
  chat_id: string;
  role: "user" | "assistant";
  content: string;
  image_url?: string | null;
  created_at: string;
};

type Profile = {
  id: string;
  display_name: string | null;
  avatar_url: string | null;
};

Errors

Server functions throw typed errors. Clients receive a JSON body with a stable code.

{ "code": "unauthorized",      "message": "Sign in required." }
{ "code": "not_found",         "message": "Chat not found." }
{ "code": "forbidden",         "message": "You don't own this chat." }
{ "code": "rate_limited",      "message": "Too many requests." }
{ "code": "validation_error",  "message": "Invalid input.", "issues": [...] }
{ "code": "ai_upstream_error", "message": "Model gateway failed." }

Rate limits (preview)

  • 60 chat messages / hour / account
  • 20 image uploads / hour / account
  • 200 read requests / minute / account

Example — send a message

import { sendMessage } from "@/lib/chats.functions";

const { reply } = await sendMessage({
  chatId: "c_01H...",
  content: "Sharp pain in my lower right abdomen for 6 hours.",
});

console.log(reply.content);

Webhooks (roadmap)

A signed webhook will fire on new severe-condition matches so clinicians can be paged. Signature verification uses HMAC-SHA256 over the raw body with a per-tenant secret.

Endpoint reference

Each server function is reachable over HTTPS at the app origin. All requests are JSON and require the Authorization header unless noted.

MethodPathPurposeAuth
GET/_serverFn/listChatsList the caller's chat threadsRequired
POST/_serverFn/createChatCreate a threadRequired
POST/_serverFn/renameChatRename a threadRequired
POST/_serverFn/deleteChatDelete a thread and its messagesRequired
GET/_serverFn/listMessagesList messages in a threadRequired
POST/_serverFn/sendMessageSend a message and get the AI replyRequired
GET/_serverFn/getProfileRead the caller's profileRequired
POST/_serverFn/updateProfileUpdate display name or avatarRequired

Authentication header

Authorization: Bearer <supabase_access_token>
Content-Type: application/json

POST /_serverFn/sendMessage — request

{
  "data": {
    "chatId": "c_01H8ZR3K2QW",
    "content": "Sharp pain in my lower right abdomen for 6 hours."
  }
}

Response — 200

{
  "reply": {
    "id": "m_01H8ZR3M7TC",
    "chat_id": "c_01H8ZR3K2QW",
    "role": "assistant",
    "content": "Right lower quadrant pain lasting hours can indicate appendicitis...",
    "image_url": null,
    "created_at": "2026-07-28T10:14:02.881Z"
  }
}

GET /_serverFn/listChats — response

[
  {
    "id": "c_01H8ZR3K2QW",
    "user_id": "u_9f2a...",
    "title": "Abdominal pain",
    "created_at": "2026-07-28T10:12:44.010Z",
    "updated_at": "2026-07-28T10:14:02.881Z"
  }
]

Error response — 401

{ "code": "unauthorized", "message": "Sign in required." }

curl example

curl -X POST https://homunculuslabs.fun/_serverFn/createChat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data":{"title":"Chest tightness"}}'