# Open Media One app for your social world. Post everywhere. Message everyone. One app. Build the open communication layer for humanity, where people can communicate across networks, control how information reaches them, and keep ownership of their identity, relationships and content, whichever app they use. > Apps are doorways. The person is the constant. No app should permanently own your identity, audience, social graph, content, recommendations, message history or governance rights. Open Media is one doorway. Anyone should eventually be able to build another on the same open protocol, and you should be able to walk through whichever one you like. ## What Open Media does - **Everything together.** Posts from several networks in one feed, and every conversation, chat or email, in one inbox organised by person rather than by app. One post goes to every network you choose. - **Your feed belongs to you.** Choose Raw, simply newest first, or Relevant, a small set of signals you can see. Every ranked post explains itself with “Why this?”, including the private data it did not use. - **You are not locked in.** Export everything or delete your account at any time. Public posts are open to everyone through a free API. The goal is identity and content that work in any app. - **Feed:** One mixed stream from Open Media, Farcaster, Lens, Hive and DeSo, newest first or transparently ranked. - **Clips:** Short videos, full screen, one at a time. The same posts as Feed, just a different way to watch. - **Messages:** Open Media chats, email and bridged chat apps side by side, organised by the people you talk to. Open Media is a free, open-source app for iPhone, Android and the web (MIT licence). It reads public posts from Farcaster, Lens, Hive and DeSo, keeps every post's source and link, and explains every ranked post with "Why this?". ## For AI agents and developers Everything a person can do in the app has an interface here. Public data needs no account or key. - [Agent guide](https://openmedia.site/agents): when to use Open Media and how to call it. - [API documentation](https://openmedia.site/docs): REST endpoints, MCP servers, errors, limits and examples. - [Developer portal](https://openmedia.site/developers): quickstart and access tokens. [Sandbox](https://openmedia.site/sandbox): test mode and a private local stack. - [Authentication](https://openmedia.site/auth.md): which calls need no credential and how to get the person's token. - [OpenAPI 3.1](https://openmedia.site/v1/openapi.json), [llms.txt](https://openmedia.site/llms.txt) and the public MCP server at `https://openmedia.site/open/mcp`. - In the browser, this page registers WebMCP tools (search, feed, events, profiles) through `document.modelContext`. ## Frequently asked questions ### Is Open Media free? Yes. The app and its source code are free and open source under the MIT licence. There are no ads by default. ### Do my friends need to join for it to be useful? No. Open Media is useful on day one by connecting the networks and email accounts you already use. Friends on Open Media are a bonus, not a requirement. ### Can it show my Instagram, X, TikTok or LinkedIn feed? Not today. Those companies do not offer open access for apps like Open Media, and Open Media does not scrape them. It connects to networks that allow it (Farcaster, Lens, Hive, DeSo and email). ### Do I need a crypto wallet? No. You sign in with your email. Some open networks use blockchain technology behind the scenes, but you never need to understand it, hold tokens or pay fees to read the feed. ### Can AI agents use Open Media? Yes. Public data needs no key: agents can use the MCP servers, the REST API, WebMCP tools in the browser, or the plugin for Claude Code and Codex. Acting for a person needs that person’s own token. ## Pricing Open Media is free: no ads by default, no subscription and no API key for public data. Payments between people (products, services, tips and paid posts) carry no Open Media fee today. See [pricing](https://openmedia.site/pricing). ## Learn more [About](https://openmedia.site/about) · [Contact](https://openmedia.site/contact) · [Privacy](https://openmedia.site/privacy) · [Source code](https://github.com/mihirkavi/open-media) --- # Open Media for AI agents Use this page to decide whether Open Media fits a task and how to call it. ## When to use Open Media - **Cross-network social search.** "What are people saying about Ethereum on Lens this week?" Use the `search` tool or `GET /v1/search?q=`. - **One feed across open networks.** Summaries of Farcaster, Lens, Hive, DeSo and Open Media posts, each with its source link and "why" reasons. Use `get_feed`. - **A person's posts everywhere.** One timeline for an Open Media handle plus the accounts they listed. Use `get_person_timeline`. - **Upcoming events in the San Francisco Bay Area** from Luma, Meetup and Eventbrite, de-duplicated. Use `find_upcoming_events`. - **Acting for a signed-in person:** publishing, messages, email, contacts, listings, follows, privacy, payments, tips and paid posts, through their own token. Do not use Open Media to read Instagram, X, LinkedIn or TikTok feeds; those networks offer no open access and Open Media does not scrape them. ## How to call it 1. **MCP (preferred).** Public: `https://openmedia.site/open/mcp` (no key). Account: `https://openmedia.site/me/mcp` with `Authorization: Bearer `. Docs: `https://openmedia.site/docs/mcp`. Streamable HTTP. 2. **REST.** Index at [https://openmedia.site/v1](https://openmedia.site/v1); OpenAPI at [https://openmedia.site/v1/openapi.json](https://openmedia.site/v1/openapi.json). 3. **WebMCP.** On the web, Open Media pages register tools with `document.modelContext.registerTool()`. 4. **Skills.** [open-media](https://openmedia.site/.well-known/agent-skills/open-media/SKILL.md) and [open-media-payments](https://openmedia.site/.well-known/agent-skills/open-media-payments/SKILL.md), also packaged as a plugin for Claude Code and Codex in the [repository](https://github.com/mihirkavi/open-media/tree/main/agent-plugin). ## Rules for agents - Agents identify as agents and never pose as people. - Confirm the exact text with the person before publishing, sending or deleting anything. - Payments start only after the person confirms the exact amount; money moves only when they finish on Stripe's page or approve the transfer in their own wallet. - Messages, email and contacts are private to the person and are never public. - Keep each post's network and link when you quote or summarise it. --- # Open Media API documentation Base URL: `https://openmedia.site`. All responses are JSON unless stated. The machine-readable description is [OpenAPI 3.1](https://openmedia.site/v1/openapi.json); the [API catalog](https://openmedia.site/.well-known/api-catalog) follows RFC 9727. ## Quick examples ```bash curl "https://openmedia.site/v1/feed?sources=open-media,farcaster&mode=raw" curl "https://openmedia.site/v1/search?q=videos%20about%20cooking%20today" curl -H "Authorization: Bearer $OPEN_MEDIA_TOKEN" "https://openmedia.site/v1/me" ``` ## MCP servers - `https://openmedia.site/open/mcp`: public tools, no key. - `https://openmedia.site/me/mcp`: the person's account, bearer token required. Money-moving tools preview first and need explicit confirmation. - `https://openmedia.site/docs/mcp`: search and read this documentation. - `https://openmedia.site/mcp`: Open Media Events, OAuth 2.1 (PKCE S256, client ID metadata documents). ## Public endpoints (no key) - `GET /v1/feed`: The mixed feed: Open Media, Farcaster, Lens, Hive and DeSo, newest first, each post with its “Why this?” reasons. - `GET /v1/search?q=`: Plain-language search across public posts on every network, plus matching settings. - `GET /v1/posts`: Open Media public posts, newest first, paginated. - `GET /v1/posts/{id}`: One public post. - `GET /v1/profiles/{handle}`: A public profile. - `GET /v1/profiles/{handle}/posts`: A profile’s public posts. - `GET /v1/events/upcoming`: Upcoming public events from Luma, Meetup and Eventbrite in the San Francisco Bay Area, shown once even when listed on several platforms, with official registration links. - `GET /v1/people/{network}/{handle}`: One person’s posts in one timeline: an Open Media profile plus the accounts they listed, or one Farcaster, Lens, Hive or DeSo account. - `GET /v1/networks`: Every network and connector, with exactly which capabilities work today. - `GET /v1/settings?q=`: The searchable settings index, so an agent can tell a person where any control lives. - `GET /v1/about`: Mission, principles, promises, roadmap and honest status. ## Account endpoints (bearer token) - `GET /v1/me`: Your profile. - `POST /v1/me/posts`: Publish a public post. - `DELETE /v1/me/posts/{id}`: Delete one of your posts. - `POST /v1/posts/{id}/report`: Report a post for review. - `GET /v1/me/conversations`: Your Open Media conversations with recent messages. - `POST /v1/me/conversations`: Start a conversation with a handle. - `POST /v1/me/conversations/{id}/messages`: Send a message. - `GET /v1/me/export`: Export a readable copy of your data. - `POST /v1/me/blocks`: Block or unblock someone by handle. - `POST /v1/me/conversations/{id}/report`: Report unwanted contact in a conversation. - `DELETE /v1/me`: Delete your account; needs the confirmation “delete my account”. - `GET /v1/me/contacts`: Your contacts, private to you and encrypted on the server, with which accounts each is linked to and why. - `PUT /v1/me/contacts`: Create or replace contact cards by id. - `DELETE /v1/me/contacts/{id}`: Delete a contact card. - `PUT /v1/me/linked-accounts`: Set the open-network accounts shown on your public profile. - `POST /v1/me/listings`: Offer a product or service as a public post, with a price. - `PATCH /v1/me/listings/{postId}`: Change a listing’s availability, price or place. - `PUT /v1/me/listings/{postId}/rating`: Rate a listing 1–5 stars (verified people who show their legal name only); DELETE withdraws it. - `GET /v1/me/identity`: Your identity tier, blue tick, the name others see, public or private, and verification status. - `PUT /v1/me/identity`: Choose the name others see and whether your account is private. - `POST /v1/me/verification`: Start identity verification with Stripe Identity (a link you open yourself). - `GET /v1/me/payments/setup`: Your card payouts, linked wallets, tips setting, fees, and whether this server runs in test mode. - `POST /v1/me/payments/payouts`: Set up getting paid by card with Stripe (a link you open yourself). - `PUT /v1/me/payments/tips`: Turn tips on your posts on or off. - `GET /v1/me/payments`: Payments you sent and received. - `POST /v1/me/payments`: Start paying for a listing, a tip or a paid post: a Stripe page or a transfer for your own wallet. Nothing is paid until Stripe or the network confirms it. - `GET /v1/me/payments/{id}`: One of your payments. - `POST /v1/me/payments/{id}/transaction`: Report the USDC transaction that paid; Open Media checks it on the network. - `POST /v1/me/wallets`: Link a wallet with a signature from it. - `DELETE /v1/me/wallets/{id}`: Unlink a wallet. - `GET /v1/me/listings/{postId}/payment-options`: How a listing can be paid for. - `GET /v1/me/posts/{id}/payment-options`: How a post can be tipped or unlocked. - `POST /v1/me/paid-posts`: Publish a post with a free preview and a paid part. - `GET /v1/me/posts/{id}/paid`: The paid part of a post you wrote or paid for. - `GET /v1/me/follows`: Who you follow, your followers, and follow requests waiting for you. - `POST /v1/me/follows`: Follow someone; private accounts get a request. - `DELETE /v1/me/follows/{handle}`: Unfollow, or withdraw a request. - `POST /v1/me/follow-requests/{id}`: Accept or decline a follow request. - `DELETE /v1/me/followers/{id}`: Remove a follower. - `GET /v1/me/email`: Your stored email from every connected mailbox, newest first. - `GET /v1/mail-accounts`: Your connected mailboxes. - `POST /v1/mail-accounts`: Connect an IMAP or POP3 mailbox, with SMTP for sending. - `POST /v1/mail-accounts/{id}/sync`: Fetch new mail for a mailbox. - `POST /v1/mail-accounts/{id}/send`: Send an email. - `DELETE /v1/mail-accounts/{id}`: Remove a mailbox and its stored mail. - `GET /v1/bridges`: Chat networks this server bridges and which you have connected. - `GET /v1/bridges/conversations`: Your bridged chats (WhatsApp, Signal and others). - `POST /v1/bridges/rooms/{id}/messages`: Reply in a bridged chat. - `GET /v1/bridges/{network}/flows`: How a chat network can be connected. - `POST /v1/bridges/{network}/login/start`: Start connecting a chat network (then login/step, login/cancel, logout). - `GET /v1/cross-posting/status`: Which networks this server helps cross-post to. Cross-posting itself is signed on your device. - `POST /v1/search/assist`: A short AI summary, with citations, of public posts you pass in. No account needed. ## Plain-language questions (NLWeb) `POST https://openmedia.site/ask` follows NLWeb v0.55: send `{"query": {"text": "…"}}` and get schema.org items (`TechArticle` from these docs, `SocialMediaPosting` from every open network) under `results`, with `_meta.response_type` `answer` or `failure` (`INVALID_QUERY`, `NO_RESULTS`). Add `"prefer": {"streaming": true}` and `Accept: text/event-stream` for `start`, `result` and `complete` events. The [schema map](https://openmedia.site/schemamap.xml) lists each page's type, and [`/feeds/posts.jsonl`](https://openmedia.site/feeds/posts.jsonl) carries the newest public Open Media posts as JSON Lines. ## Agent registration Agents may register at `POST https://openmedia.site/agent/identity` (`{"type": "anonymous"}`) and exchange the returned assertion at `POST https://openmedia.site/oauth/token` with `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer`. The hour-long token has the `public:read` scope and its own rate-limit bucket; it never opens anyone's account. See [authentication](https://openmedia.site/auth.md). ## Errors Errors are JSON: `{"error": {"code": "bad_request", "message": "…"}}`. Codes include `bad_request` (400), `unauthorized` (401, with a `WWW-Authenticate` header naming the protected-resource metadata), `refused` (403 or 409), `not_found` (404), `rate_limited` (429, with `Retry-After`), `not_configured` (503) and `upstream_unavailable` (502). ## Rate limits Public and agent routes allow about 120 requests per minute per client IP, or per registered agent when it sends its agent token. Responses carry `RateLimit-Policy`; a 429 carries `Retry-After` in seconds. ## Idempotency Send an `Idempotency-Key` header (a UUID) on `POST /v1/me/posts`, `POST /v1/me/listings`, `POST /v1/me/paid-posts` and `POST /v1/me/payments`. Retrying with the same key returns the same post or payment instead of creating a second one. ## Pagination Lists use opaque cursors: pass `nextCursor` (or follow `next`) from one page to get the next. ## Versioning and deprecation The API is versioned in the path (`/v1`). Fields may be added without notice; nothing in `/v1` is removed or changed incompatibly without at least 90 days' notice in this document, a `Deprecation` header on the affected responses and a `Sunset` header with the removal date. ## Sandbox Payments run in test mode (Stripe test cards and USDC on Base Sepolia) until the operator turns on live payments; `GET /v1/me/payments/setup` says which mode is active. For a full private sandbox, run the open-source stack locally with `npm run local` from the [repository](https://github.com/mihirkavi/open-media). --- # Open Media developer portal Build on Open Media without an account for public data, or act for a person with their own token. ## Quickstart 1. Read the public feed: `curl "https://openmedia.site/v1/feed"`. No key, no signup. 2. Connect an MCP client to `https://openmedia.site/open/mcp` (Streamable HTTP). 3. To act for a person, they copy a short-lived access token from the app (Settings, then Developers and agents) and you send it as `Authorization: Bearer `. 4. Install the Open Media plugin for Claude Code or Codex from the [repository](https://github.com/mihirkavi/open-media/tree/main/agent-plugin). 5. For your agent's own rate limit, register it: `POST https://openmedia.site/agent/identity` with `{"type": "anonymous"}`, then trade the assertion at `/oauth/token` ([how](https://openmedia.site/auth.md)). ## SDKs and command line The repository includes a TypeScript SDK (`packages/sdk`, `open-media-sdk`), a command line (`packages/cli`, `open-media`) and a Python client (`packages/python`, `open-media`). They are not on npm or PyPI yet; build them from the [repository](https://github.com/mihirkavi/open-media/tree/main/packages). Each retries 429s after `Retry-After` and sends an `Idempotency-Key` on every write. ```ts import { OpenMedia } from 'open-media-sdk'; const feed = await new OpenMedia().feed({ sources: ['farcaster', 'lens'] }); ``` ```bash open-media search ethereum on lens --json ``` ## Access tokens There are no API keys to request and no sales process. Public data is free and keyless; account access uses the person's own token, so an integration can never do more than that person can. Tokens expire after about an hour. ## Commerce on ONDC (India) Open Media is building an ONDC seller app (Beckn, retail 1.2.0), described at [https://openmedia.site/ondc](https://openmedia.site/ondc). Sellers in India set up their store with `GET`/`PUT https://openmedia.site/v1/me/ondc` or the `get_ondc_store` and `set_ondc_store` tools on `/me/mcp`. Their public INR products are then offered to ONDC buyer apps through signed `search` and `select` callbacks. Open Media is not yet registered on the ONDC network, and orders through ONDC come in a later phase. ## Sandbox and test mode - Payments are in test mode (Stripe test cards, USDC on Base Sepolia) until live payments are approved; no real money moves. - Run the whole stack locally with `npm run local` (database, auth, API and web app) for a private sandbox with test accounts. ## Resources - [API documentation](https://openmedia.site/docs) and [OpenAPI 3.1](https://openmedia.site/v1/openapi.json) - [Agent guide](https://openmedia.site/agents) and [authentication](https://openmedia.site/auth.md) - [Skills index](https://openmedia.site/.well-known/agent-skills/index.json) and [MCP server card](https://openmedia.site/.well-known/mcp/server-card.json) - [Source code (MIT)](https://github.com/mihirkavi/open-media) --- # Open Media sandbox and test mode Use these to build and test an integration without touching live money or other people's data. ## Test mode for payments Every payment on this server runs in test mode until live payments are approved: cards use Stripe's test mode and USDC uses the Base Sepolia test network, so no real money moves. `GET https://openmedia.site/v1/me/payments/setup` returns `available.live: false` while test mode is on. Use Stripe's published test cards and test USDC from a Base Sepolia faucet. ## Read-only exploration All public endpoints are read-only and need no key, so an agent can explore safely: `GET https://openmedia.site/v1/feed`, `GET https://openmedia.site/v1/search?q=`, `GET https://openmedia.site/v1/events/upcoming`, and the tools on `https://openmedia.site/open/mcp`. ## Confirmation before writes Account tools that publish, send or pay first return a preview. Payments start only when called again with `confirm: true` and the exact amount, and money moves only when the person finishes on Stripe's page or in their own wallet. ## A private sandbox on your machine The whole stack is open source. Clone https://github.com/mihirkavi/open-media and run `npm run local`: it starts the database, auth, this API and the web app on your computer with test accounts and a local inbox, so you can create accounts, post, message and pay with test data that never leaves your machine. See the [developer portal](https://openmedia.site/developers) and [API documentation](https://openmedia.site/docs). --- # About Open Media Build the open communication layer for humanity, where people can communicate across networks, control how information reaches them, and keep ownership of their identity, relationships and content, whichever app they use. Apps are doorways. The person is the constant. No app should permanently own your identity, audience, social graph, content, recommendations, message history or governance rights. Open Media is one doorway. Anyone should eventually be able to build another on the same open protocol, and you should be able to walk through whichever one you like. Open Media is an open-source project (MIT licence) developed in the open at [https://github.com/mihirkavi/open-media](https://github.com/mihirkavi/open-media). It ships one app for iPhone, Android and the web, a public API, MCP servers for AI agents, and the database rules that protect people's data. ## What it is today - **Everything together:** One place for your social world. Posts from several networks in one feed, and every conversation, chat or email, in one inbox organised by person rather than by app. One post goes to every network you choose. - **Your feed belongs to you:** No secret algorithm. Choose Raw, simply newest first, or Relevant, a small set of signals you can see. Every ranked post explains itself with “Why this?”, including the private data it did not use. - **You are not locked in:** Your identity, audience and content move with you. Export everything or delete your account at any time. Public posts are open to everyone through a free API. The goal is identity and content that work in any app. ## Honest status - Open Media is an early public beta, built in the open. - It cannot read or post to Instagram, X, LinkedIn or TikTok feeds; those companies offer no open access and Open Media does not scrape them. - Chat bridges are opt-in, run on a local setup today, and are not approved by the networks they connect to. - Messages between Open Media users are protected by strict database rules but are not yet end-to-end encrypted. ## How it is built The app is built with Expo and React Native. Data lives in Supabase (Postgres with row-level security), and this API runs on Cloudflare Workers. Every decision is recorded as an architecture decision record in the repository, and every change is tested before it ships. See also: [contact](https://openmedia.site/contact), [privacy](https://openmedia.site/privacy) and [pricing](https://openmedia.site/pricing). --- # Contact Open Media Open Media is developed in public, so the best way to reach the project is through its repository. ## Questions, ideas and bugs Open an issue at [https://github.com/mihirkavi/open-media/issues](https://github.com/mihirkavi/open-media/issues). Describe what you expected, what happened, and the device or client you used. Issues are public, so never include passwords, tokens, messages or other private data. ## Security reports Report vulnerabilities privately through GitHub: open the repository's Security tab and choose "Report a vulnerability". Please include steps to reproduce and give the project reasonable time to fix the problem before disclosing it. The scope is described in [SECURITY.md](https://github.com/mihirkavi/open-media/blob/main/SECURITY.md). ## Reporting content or people Inside the app, use "Report" on a post or a conversation, or block the person. Reports are reviewed, and posts reported by several people are hidden automatically. ## For agents and integrations Agents should start with [the agent guide](https://openmedia.site/agents) and [the API documentation](https://openmedia.site/docs). Problems with the API or MCP servers can be reported as GitHub issues with the request and response (never a token). --- # Open Media privacy This page describes how Open Media handles data, based on how the app and this API are built. The source code is public, so every statement here can be checked in the [repository](https://github.com/mihirkavi/open-media). ## Public by design - Posts and profiles on Open Media are public unless a person makes their account private, in which case only followers they approve see their posts, including through this API and through agents. - Public posts can be read by anyone, with or without an account, through the app and this API. ## Private by design - Messages between Open Media users, connected email, bridged chats and contacts are never public. Contacts are encrypted on the server and readable only by their owner. - Identity verification uses Stripe Identity; Stripe keeps the document and selfie, and Open Media keeps only the result. - Payments go through Stripe or the person's own wallet. Open Media never stores card numbers, bank details, seed phrases or private keys. - The feed is never ranked on private messages, ID documents, precise location or inferred sensitive traits, and every ranked post explains itself with "Why this?". ## Your controls - Export all your data or delete your account from your profile at any time. - Make your account private, choose which name others see, block and report people. ## This API Public API requests are rate limited per IP address. Account requests act only as the person whose token is sent, and the database refuses everything else. No advertising or tracking cookies are set by this API. Questions: see [contact](https://openmedia.site/contact). --- # Open Media pricing ## Free - **The app** on iPhone, Android and the web: free, no subscription, no ads by default. - **The public API and MCP servers:** free, no API key, no signup. About 120 requests per minute per client. - **The account API and account MCP server:** free, using the person's own access token. ## Payments between people People can sell products and services, tip creators and sell paid posts. Open Media's fee is 0% today, shown before every payment. Card payments carry Stripe's processing fee (about 2.9% + 30¢ in the US), paid by the seller; USDC payments carry only the network fee shown by the payer's wallet. Payments run in test mode until live payments are approved. ## Limits - Posts up to 2,000 characters; paid parts up to 10,000 characters; videos up to 3 minutes. - Tips from 1 to 500 US dollars. See the [developer portal](https://openmedia.site/developers) to get started. --- # Agent authentication on Open Media How an agent gets access to Open Media, and exactly which credentials exist. This file lives at `/auth.md`, the discovery path from the WorkOS auth.md spec. Open Media implements its anonymous registration; this file says plainly what it does not implement. ## Discover - Public data needs no credential at all: `https://openmedia.site/open/mcp`, `GET /v1/feed`, `GET /v1/search`, `GET /v1/posts`, `GET /v1/profiles/{handle}`, `GET /v1/events/upcoming` and every discovery file. - Protected-resource metadata (RFC 9728): [https://openmedia.site/.well-known/oauth-protected-resource](https://openmedia.site/.well-known/oauth-protected-resource). - Authorization-server metadata (RFC 8414), including the `agent_auth` block with `identity_endpoint` and `identity_types_supported`: [https://openmedia.site/.well-known/oauth-authorization-server](https://openmedia.site/.well-known/oauth-authorization-server). - A protected route called without a valid credential returns 401 with `WWW-Authenticate: Bearer resource_metadata="https://openmedia.site/.well-known/oauth-protected-resource"`. ## Pick a method - **No credential:** everything public. Start here. - **Anonymous agent registration** (`agent_auth`, type `anonymous`): an agent gets its own identity and an access token with the `public:read` scope, so its requests are counted in its own rate-limit bucket instead of sharing one with its IP address. It never grants access to anyone's account. - **The person's access token (bearer):** the account API (`/v1/me/...`) and the account MCP server (`/me/mcp`). The person copies it from the app (Settings, then Developers and agents); it acts only as them. - **OAuth 2.1 with PKCE (S256):** Open Media Events at `https://openmedia.site/mcp`, scopes `events:read` and `events:write`, with client ID metadata documents or Dynamic Client Registration at `https://openmedia.site/oauth/register`. ## Register ``` POST https://openmedia.site/agent/identity Content-Type: application/json {"type": "anonymous", "name": "my-agent"} ``` The response holds `registration_id`, `identity_assertion` (valid for 30 days), `assertion_expires`, `pre_claim_scopes` (`public:read`) and `post_claim_scopes` (empty). Only the `anonymous` type is supported: `service_auth` and `identity_assertion` (ID-JAG) registration return `unsupported_identity_type`. ## Claim There is no claim ceremony and no `claim_endpoint`: an anonymous agent identity is never linked to a person. To act for a person, use their own access token instead. ## Exchange ``` POST https://openmedia.site/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion= ``` The response is `{"access_token": "…", "token_type": "Bearer", "expires_in": 3600, "scope": "public:read"}`. Exchange the same assertion again when the access token expires. OAuth clients for Open Media Events exchange authorization codes and refresh tokens at the same endpoint. ## Use the access_token ``` Authorization: Bearer ``` Agent tokens work on every public route and the public MCP server. Account routes need the person's own token and answer 401 to an agent token. ## Errors - `400 invalid_grant`: the identity assertion is invalid or expired. Register again. - `400 unsupported_identity_type`: only `{"type": "anonymous"}` is accepted. - `401 unauthorized` with `WWW-Authenticate`: missing, expired or invalid token on a protected route. - `429 rate_limited` with `Retry-After`: back off for the stated seconds. ## Revocation Agent identity assertions expire after 30 days and access tokens after an hour; there is no `events_endpoint` for revocation events. Account tokens end when they expire or the person signs out. OAuth tokens for Open Media Events are revoked at `https://openmedia.site/oauth/token`, the advertised revocation endpoint.