API

Developers

The landscape API, the Markdown twins of every page, and the OAuth 2.1 server behind the publisher tools.

Developers

FellowMakers.app exposes three programmable surfaces: an HTTP API described by an OpenAPI document, a Model Context Protocol (MCP) endpoint for AI agents, and an OAuth 2.1 authorization server that issues the tokens both accept. Everything on this page is served by the same deployment, so the URLs are live wherever you are reading this.

Start here

WhatWhereFormat
OpenAPI 3.1 document/openapi.jsonapplication/json
API root/apiJSON index of the surfaces below
MCP endpoint/mcp (POST, Streamable HTTP)JSON-RPC
MCP server card/mcp/server-cardapplication/mcp-server-card+json
MCP Registry manifest/server.jsonapplication/json
Authorization server metadata/.well-known/oauth-authorization-serverRFC 8414
Protected resource metadata/.well-known/oauth-protected-resourceRFC 9728
API catalog/.well-known/api-catalogRFC 9727 linkset
Agent guidance/llms.txtMarkdown
Sitemap/sitemap.xmlXML

Every public page also has a Markdown twin: add .md to its path, or send Accept: text/markdown.

Calls that need no token

curl https://fellowmakers.app/api/health
curl https://fellowmakers.app/api
curl https://fellowmakers.app/openapi.json

The health check reports which environment answered. The discovery documents above are public as well.

Authorization

The API and the MCP endpoint accept bearer tokens issued by this deployment's own authorization server. The flow is OAuth 2.1: authorization code with PKCE (S256), refresh tokens, and revocation. There is no API-key form and no sales contact: a client registers itself, and the person signing in approves what it may do.

1. Register a client

Registration is open, as RFC 7591 intends, and immediate:

curl -X POST https://fellowmakers.app/api/oauth/register \
  -H 'Content-Type: application/json' \
  -d '{"client_name":"My agent","redirect_uris":["http://127.0.0.1/callback"],"token_endpoint_auth_method":"none"}'

The response carries the client_id and a registration access token for updating or deleting the registration later. Clients that publish a Client ID Metadata Document can use its URL as the client_id instead of registering.

2. Ask the person for consent

Send the browser to the authorization endpoint from the metadata document with response_type=code, your client_id, a redirect_uri you registered, a PKCE code_challenge, the scope you need and, for MCP, resource=https://fellowmakers.app/mcp. The person signs in with Google and approves or declines.

3. Exchange the code

curl -X POST https://fellowmakers.app/api/oauth/token \
  -d grant_type=authorization_code \
  -d code=... -d client_id=... -d redirect_uri=... -d code_verifier=...

Present the access token as Authorization: Bearer .... By default it lives an hour; the refresh token lives thirty days from consent, is single-use, and rotating it never extends that window, after which the person signs in again. Refresh with grant_type=refresh_token; revoke at the revocation endpoint. A request without a valid token answers 401 with a WWW-Authenticate header that points at the protected resource metadata, which is how a client finds this authorization server on its own.

Scopes

ScopeGrants
openidConfirm who you are
profileSee your name
emailSee your email address
readRead your data
writeChange your data on your behalf

Reads need read; anything that changes data needs write. A token is limited to the scopes the person approved, and the person can revoke it from their profile at any time.

MCP

The endpoint is /mcp over Streamable HTTP. Unauthenticated initialize succeeds and reports the server's capabilities; everything else needs a bearer token bound to the /mcp resource. Hosted clients such as Claude, ChatGPT and Codex connect by URL, register themselves and open the consent page; nothing is configured on this side.

MCP requires read scope. Search projects or waves in any language, then get project details. Queries are recorded (Privacy); personal profiles are excluded:

  • get_project: Get a project by slug, its captured website information and related projects for analysis. Does not return builders, personal profiles or personal evidence. (read-only)
  • search_projects: Search products by meaning, problem or audience, with source excerpts. Optional sector and limit. Queries are recorded. Use get_project for details. (read-only)
  • search_waves: Search shared ideas across projects. Returns wave summaries. Optional group and limit. Queries are recorded. (read-only)

Tools marked read-only can run without confirmation. Call tools/list for the current schemas; the server card lists the protocol versions it speaks. A call that fails is a result with isError rather than a protocol error, and its structuredContent is always the same shape: code, message, retryable, and details with the HTTP status and, for a scope refusal, the scope that was missing.

Sandbox

The stage environment runs the same code against its own database and object store:

curl https://landscape-stage.krasnoperov.me/api/health

Register clients, sign in and exercise the API there without touching production. Its discovery documents point at itself, so a client configured for the sandbox never leaks into production by accident.

Command line

The repository ships a CLI that signs in through the browser, stores the tokens and can bridge a local MCP client to the deployed endpoint over stdio:

pnpm run cli login
pnpm run cli mcp
pnpm run cli login --env stage

Versioning

The API is versioned by date, and the current version is 2026-09-10. Send API-Version: 2026-09-10 to pin a client to the version it was written against, or omit the header to get the current one. Every response under /api carries API-Version naming the version that answered, and a request naming a version that does not exist is refused with 400 unsupported_version rather than served something it did not ask for.

A version leaves in two steps. A breaking change ships under a new date, and the previous date keeps answering for at least ninety days as a deprecated version: every response to a request that pins it carries a Deprecation header (RFC 9745: @ and Unix seconds) naming the day it was deprecated, a Sunset header (RFC 8594) naming the last day it answers, and a Link with rel="deprecation" pointing here. After the sunset day the version is removed and a request that still pins it is refused with 400. The current version never carries these headers, so a client can watch for Deprecation alone.

Rate limits

Limits are per minute, per bucket, and enforced at the edge. Every response under /api names the policy it passed under in RateLimit-Policy and RateLimit-Limit; a refused request answers 429 with Retry-After and a RateLimit header showing the bucket empty.

BucketRequests per minute
Authorization, client registration and client configuration, per address20
Token and revocation requests, per client and address600
MCP tool calls, per person and address60
Every other API request, per address1200

Errors

Every error under /api has one shape, ApiError in the OpenAPI document: error is a short code where one exists and a sentence otherwise, and error_description, when present, says more for a person. The OAuth endpoints use the RFC 6749 codes (invalid_request, invalid_client, invalid_grant, slow_down). A request without a valid token answers 401 with a WWW-Authenticate header that points at the protected resource metadata; a valid token without the needed scope answers 403 insufficient_scope. Unknown paths answer 404, with a JSON body under /api that names the OpenAPI document and a Markdown body elsewhere that says where to look next.

Getting help

Integration questions go to hello@fellowmakers.app. Vulnerabilities go to the same address, as described in /.well-known/security.txt.