The public API and MCP server are live.
Versioned REST API, 177 operations across 26 domains, reads and writes. Hosted MCP server. Key or JWT auth. Live reference below.
Public REST API
api.freelance-os.fr, versioned /v1. 177 operations across 26 domains, reads and writes. Auth via X-API-Key (partners, scripts, mobile) or session JWT (web and mobile). Keys are workspace-scoped automatically, otherwise the workspace goes in the {workspaceId} path. Responses are { data }, errors are typed with a stable code. OpenAPI 3.1 spec and live interactive reference at api.freelance-os.fr/v1/docs.
- CRM: contacts, deals, segments, 360 view, interactions
- Workbench: projects, tasks, milestones, KPIs
- Counsel: quotes, contracts, invoices and line items
- Booking and aggregated calendar: day agenda, week and month view
- Inbox: threads, messages, conversations
- Studio, Collections, Programme, Products, Analytics
- Email, Calls, Webinars, LinkedIn, AI Visibility, Copilot
- Identity, public plans, API key management
Reliability: idempotency, pagination, rate limit
Built for mobile and native clients on flaky networks. Send an Idempotency-Key header on your POST, PATCH and DELETE: a retry replays the same response instead of creating a duplicate. Large lists (contacts, records, inbox, calls) paginate by cursor: pass cursor and read pagination.next_cursor until has_more is false. 120 req/min sliding-window rate limit, X-RateLimit-* headers on every response.
- Idempotency-Key: retry dedup, 409 if the same call is already in flight
- Keyset cursor pagination: { data, pagination: { next_cursor, has_more } }
- Rate limit 120 req/min, 429 when exceeded
MCP server
A hosted Model Context Protocol server. Wire Freelance OS to Claude Code, Cursor, ChatGPT, Claude Desktop in one command from /settings/mcp. 200+ tools, OAuth 2.1 + DCR, JIT approval on destructive actions, per-workspace audit log.
- Full-text search across all modules
- Draft creation from the agent
- Read call transcripts
- Mutate deals and tasks
- Orchestrated multi-module workflows
API keys
Generate long-lived workspace-scoped keys from /settings/api-keys. Format fos_sk_live_<token>, sha256-hashed at rest, scopes (read:* / write:* / *), optional expiration. The plaintext shows once. A key can also name a site, which is what the /v1/end-user routes require: those are how your app signs in its own users. An API client has no host to resolve the site from, so the key carries it.
Sign in your app's own users
Your app has its own users, and Freelance OS can be their authentication backend. You create a key that names one of your sites, your app calls /v1/end-user with it, and everyone who signs up belongs to that site and to no other. The same address can be a customer of two of your sites with two different passwords, or share one account if you ask for it. For a mobile app, the native Google SDK returns an identity token you post as-is: no redirect, no client secret, and the person comes out with a verified address since Google just proved it. Signup and login return a token pair: a short access token for the Authorization: Bearer header, and a refresh token to store. Refreshing rotates both, and an already-consumed token that shows up again cuts the whole lineage: the person signs in again, so does whoever stole it, and nobody stays inside quietly.
- POST /v1/end-user/signup and /login: the token pair
- POST /v1/end-user/oauth/google: the native Google SDK token, exchanged for the same pair
- POST /v1/end-user/refresh: rotation, and reuse detection
- GET /v1/end-user/me, PATCH for the name, DELETE for the account
- Password: /password/change, /password/reset-request, /password/reset-confirm
- Email: /verify-request and /verify-confirm, verification is per site
- Subscriptions: GET /subscriptions, POST /subscriptions/cancel, POST /billing-portal
Storing and reading your users' data
A collection is a table you define in Freelance OS, and your users can write to it from your app. Two reads, never one: the PUBLISHED records, which everyone sees, and THEIR OWN, which only they see. That distinction is what avoids the classic trap, a "my items" list that actually returns everybody's. Every write is bounded by the signed-in person: they cannot edit or delete a record that is not theirs, and an attempt returns 404 rather than 403, because a 403 would confirm the record exists. Writes are capped at 60 per minute per collection, the same cap a site applies, so that a second surface does not become a way around the first.
- GET /v1/end-user/collections: the collections open to your audience
- GET /v1/end-user/collections/{slug}/records: the published records
- GET /v1/end-user/collections/{slug}/records/mine: their own, published or not
- POST /v1/end-user/collections/{slug}/records: create one
- PATCH and DELETE /v1/end-user/collections/{slug}/records/{recordId}: theirs only
Realtime rooms
A room is a space your users join live. Freelance OS holds the identity and the right to enter, a media server holds the sound: you ask for a token, you hand it to your SFU, and that is the whole integration. The room's technical name is prefixed by your site, so two customers who both call a room "general" never end up in the same one. You create rooms from a site's Rooms screen, or through the copilot. A room can be reserved for the subscribers of one of your plans: the door becomes the subscription, checked when the token is requested, and the token expires after an hour.
- GET /v1/end-user/rooms: the site's rooms, and which are open
- POST /v1/end-user/rooms/{slug}/token: the entry token, and the media server address
- A closed room refuses entry without leaving the inventory
Webhooks
Roadmap Q3 2026. Set target URLs per workspace, pick the events you want. Signed payloads. Exponential retry. Event logs visible in /settings/webhooks.
- contact.lifecycle_stage_changed
- deal.stage_changed
- invoice.paid
- booking.created
- draft.published
Connect your site
Wire any external site to a Freelance OS form without rebuilding a backend. Publish the form, add your site domain to the form's allowed origins, then copy the two snippets from the form page: the POST to /api/forms/submit (leads land in the CRM, the internal-notify and prospect-confirmation actions run inside FOS) and the px.js pixel for tracking. Each form is workspace-scoped, and so is the CORS allowlist: two workspaces never see each other.
- Allowed origins: form editor, settings, domains
- Submit snippet + pixel: the form page, copy-paste
- GET /api/forms/schema?formId=... returns the field shape (id, label, type, options)
- Check your mapping at your site build to block any form drift
SDK
Auto-generated TypeScript client from the OpenAPI spec, end-to-end typed. For other languages, use the OpenAPI 3.1 spec at api.freelance-os.fr/v1/openapi.json with your preferred generator.
Need help?
Keys, scopes, webhooks, partner integration, we help you directly. Book a slot.