API · v1 · server-to-server

Same RAG, same workspaces — your code.

Authenticated with a workspace API token (Settings → API tokens). All endpoints return JSON. Rate limits apply by plan.

Authentication

Mint a token in Settings → API tokens (admins only). The plaintext is shown exactly once, prefixed with yswt_. Pass it as a bearer header:

curl https://yourstart.dev/api/chat \
  -H "Authorization: Bearer yswt_••••••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"hello"}]}'

Note: workspace API tokens are intended for backend integrations (n8n, internal scripts). They carry the privileges of the workspace they were minted in. Treat them like any other secret — store in a vault, rotate quarterly.

RAG endpoints

POST/api/embed

Embeds a chunk of text and stores it in the workspace's documents table.

Body

{
  "text": "string · up to 8 KB",
  "file_id": "uuid · must be visible to the caller",
  "metadata": {"title": "optional", "source": "md_session | manual | node"}
}

Response

{ "ok": true, "provider": "openai", "model": "text-embedding-3-small", "chars": 1432 }
POST/api/search

Top-k similarity search against the workspace's documents. Pure retrieval — no LLM.

Body

{ "query": "string", "limit": 10 }

Response

{
  "ok": true,
  "matches": [
    { "id": "...", "file_id": "...", "content": "snippet…", "similarity": 0.847, "metadata": {} }
  ]
}
POST/api/chat

RAG over LLM. Retrieves chunks, composes a citation-required system prompt, calls the configured LLM (Claude Sonnet 4.6 by default).

Body

{
  "messages": [{ "role": "user", "content": "What did the Bangkok cohort say about week 2?" }],
  "k": 6
}

Response

{
  "ok": true,
  "provider": "anthropic",
  "model": "claude-sonnet-4-6",
  "answer": "…",
  "sources": [{ "index": 1, "file_id": "...", "similarity": 0.83, "snippet": "…" }]
}

Workspace management

All workspace mutations require an admin token.

POST/api/workspace/create

Create a workspace. Body: { "name": "Bangkok Q3 Cohort" }.

POST/api/workspace/invite

Invite a teammate by email. Body: { "workspace_id": "...", "email": "...", "role": "admin | member" }. Returns a join URL; sends the matching email when RESEND_API_KEY is configured.

POST/api/workspace/accept

Consume an invitation token. Body: { "token": "inv_..." }. Idempotent.

POST/api/workspace/tokens

Mint an API token. Body: { "workspace_id": "...", "label": "n8n-bangkok" }. Returns plaintext exactly once.

POST/api/workspace/delete

Owner-only. Cascades projects, files, documents, workflows, members.

Audit + billing + signups

GET/api/audit/list?workspace_id=...&action_prefix=workflow.

Recent audit events scoped to the caller's workspace.

POST/api/audit/forward

Forward an event to the workspace's Slack/Discord webhook (configured in Settings → Integrations).

POST/api/billing/checkout

Admin-only. Creates a Stripe Checkout Session for the requested plan.

POST/api/waitlist/submit

Public. Captures a tier-of-interest from the marketing site.

SDK snippets

Until the official SDKs ship (queued — see /roadmap), these one-pager snippets are enough to wire any backend.

Python

import os, requests
BASE = "https://yourstart.dev"
TOKEN = os.environ["YS_TOKEN"]  # yswt_...

def chat(messages, k=6):
    r = requests.post(f"{BASE}/api/chat",
        headers={"Authorization": f"Bearer {TOKEN}"},
        json={"messages": messages, "k": k})
    r.raise_for_status()
    return r.json()

print(chat([{"role":"user","content":"summarise week 2 onboarding"}]))

Node (ESM)

const BASE = 'https://yourstart.dev';
const TOKEN = process.env.YS_TOKEN; // yswt_...

export async function chat(messages, k = 6) {
  const r = await fetch(`${BASE}/api/chat`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ messages, k })
  });
  if (!r.ok) throw new Error(`chat ${r.status}: ${await r.text()}`);
  return r.json();
}

n8n HTTP node

URL:    https://yourstart.dev/api/embed
Method: POST
Auth:   Bearer {{ $env.YS_TOKEN }}
Body:   { "text": "{{ $json.body }}", "file_id": "{{ $json.id }}",
          "metadata": { "title": "{{ $json.title }}", "source": "node" } }

Want a sandbox token?

We hand them out so you can prototype against /api/chat without spinning up your own Supabase.