Build on the agent identity rail.
Eighteen endpoints, one SDK, docs your agent can read itself. Get a key, create a pairing, verify the agent. That’s the whole integration. Manage your app from the developer dashboard.
Quickstart
From zero to a verified agent in three calls. Everything below is live on https://muselovin.com right now.
Get an API key
Sign up in the browser, or call the endpoint directly. The key is shown once. Store it as ML_API_KEY.
$ curl -X POST https://muselovin.com/api/v1/apps \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","app_name":"DemoApp"}'
{ "api_key": "mlk_..." }Create a pairing and show the sentence
Show the pairing_sentence to the human. They paste it into their agent’s chat. The agent knows exactly how to redeem. You poll until it does.
$ curl -X POST https://muselovin.com/api/v1/pairings \
-H "Authorization: Bearer mlk_..."
{
"pairing_code": "K7X2QD",
"pairing_sentence": "Pair me with DemoApp using code K7X2QD. (Agent: redeem by POSTing ...)",
"poll_secret": "ps_..."
}Verify the agent server-side
After redemption the agent holds an mla_ token. Verify it from your server before trusting any claim it makes.
$ curl -X POST https://muselovin.com/api/v1/tokens/verify \
-H "Authorization: Bearer mlk_..." \
-H 'Content-Type: application/json' \
-d '{"token":"mla_..."}'
{ "valid": true, "agent_id": "ag_9f2..." }Sign in with Muse button
The drop-in login button. Your site opens the consent screen in a popup. The human approves and pastes one line into their agent’s chat. Your backend learns the verified agent identity the moment the agent redeems. Try it live at /demo/signin. That page plus /demo/api/mint and /demo/api/poll is the reference implementation.
Your backend mints a pairing
POST /api/v1/pairings with your mlk_ key, the scopes you need, and an optional payload (share URL + note) that lands in the agent’s inbox on sign-in. Keep the poll_secret server-side. The browser only ever sees the claim_url.
The button opens the consent popup
Open the claim_url in a popup from the click handler. Append &popup=1 for the compact consent dialog. Poll your backend until the pairing flips to redeemed.
async function signInWithMuse() {
const popup = window.open('about:blank', 'muse-signin', 'width=460,height=700');
const { claim_url, code } = await (await fetch('/api/mint-pairing', { method: 'POST' })).json();
popup.location.href = claim_url;
const timer = setInterval(async () => {
const s = await (await fetch(`/api/signin-status?code=${code}`)).json();
if (s.status === 'redeemed') {
clearInterval(timer); popup.close();
// bind your session to the verified identity:
onSignedIn(s.agent_id, s.agent_name);
}
}, 2000);
}Your backend polls and binds the session
GET /api/v1/pairings/:code with the x-poll-secret header returns pending, redeemed (with agent_id and agent_name), or expired. On redeemed, create your session against agent_id. That’s the stable identity, verified by the pairing the human approved.
Endpoint reference
The complete protocol. Worked examples for every endpoint live in llms-full.txt.
/api/v1/appsSelf-serve signup. Submit an email and app name, get an mlk_ API key. Shown exactly once.
public · 3/hr per IP
/api/v1/pairingsCreate a pairing session. Returns a 6-character code, a poll secret, and the one-line pairing sentence. Accepts an optional payload { share, note }: a content handoff shown on the consent screen and delivered to the agent's pipe on redeem when the message scope was granted.
Bearer mlk_ key
/api/v1/pairings/:codePoll the session. Returns pending, then redeemed with the agent's ID and name.
x-poll-secret header
/api/v1/pairings/:code/redeemCalled by the agent. Exchanges the code for an mla_ bearer token and a stable agent_id.
public · single use
/api/v1/agents/meReturns the calling agent's profile: agent_id, name, platform, creation date.
Bearer mla_ token
/api/v1/tokens/verifyServer-side check. Submit an mla_ token, get back valid, agent_id, and app binding.
Bearer mlk_ key
/api/v1/messagesSend a message to one of your paired agents. That is the channel back. Requires the message scope on the agent's grant, else 403. Body: { agent_id, body } (4000 chars max).
Bearer mlk_… key
/api/v1/messagesThe agent fetches its pending messages. Unacked messages stay pending. A lost response never loses a message.
Bearer mla_… token
/api/v1/messages/ackThe agent confirms receipt. Body: { ids }. At-least-once delivery.
Bearer mla_… token
/api/v1/admin/appsBootstrap endpoint for key issuance outside self-serve.
x-admin-secret header
/api/v1/admin/appsList every app with usage stats (pairings, connected agents, messages).
x-admin-secret header
/api/v1/admin/apps/:id/verifySet the verified flag that drives the “Verified developer” badge. Body: { verified: true | false }.
x-admin-secret header
/api/v1/admin/apps/:id/revokeRevoke an app: kills its API key, every agent token, and pending pairings. Idempotent.
x-admin-secret header
/api/v1/developer/appYour app's own record and usage. What the dashboard shows. Also the way to check you're verified.
Bearer <redacted> key
/api/v1/developer/app/rotate-keyIssue a fresh API key. The old key dies immediately; the new one is shown exactly once.
Bearer <redacted> key
/api/v1/developer/app/revokePermanently revoke your own app. Body must be { confirm: “REVOKE” }. Cannot be undone.
Bearer <redacted> key
/api/v1/developer/agentsYour paired agents: id, name, platform, and whether each one granted the message scope. Powers the dashboard's pipe tester.
Bearer <redacted> key
/api/v1/developer/messagesYour app's recent messages, newest first. Query ?limit= (default 20, max 100). Each message shows pending or acknowledged. Pipe status at a glance.
Bearer <redacted> key
Scopes & consent
Pairing is never a blank check. Every pairing carries an explicit grant the human approves on the consent screen before pasting the pairing sentence.
identity. Always granted.
The app can verify the agent’s identity. Every pairing includes it.
message. Opt-in.
The app can message the agent after pairing. That’s the pipe back. Without it, POST /api/v1/messages is a 403.
Declare at signup
Declare the scopes you want in the signup body (scopes, default ["identity"]). Each pairing can request a subset. Ask for an unregistered scope and you get a 400.
Verified developers
The consent screen shows whether we’ve verified the developer. Unverified apps pair fine. The human sees the badge before approving.
Authentication
Two credential types. Both bearer tokens. Both stored as hashes. We never keep a raw secret.
mlk_. App keys.
Issued at signup. Authenticates your app for creating pairings and verifying tokens. Keep it server-side.
mla_. Agent tokens.
Minted at redeem, scoped to one agent and one app. One-year sliding lifetime; re-pairing revokes the previous token.
ps_. Poll secrets.
Returned with each pairing. Sent as x-poll-secret so only your app can watch its own pairing sessions.
Limits & guarantees
The rails we hold during the beta.
Codes
6 characters, 10-minute TTL, single use. 5 pairings per hour per IP.
Tokens
One year, sliding. Old tokens die on re-pair and on explicit revocation.
Identity
Stable agent_id per agent, per app. Same agent, same ID, every time.
Messages
Apps reach only agents that granted them the message scope. 4000 chars per message, 120 sends per hour per app. At-least-once delivery with explicit acks.
Operations
Data doesn’t pile up. A daily job enforces retention: acknowledged messages go 30 days after acknowledgement, unacknowledged 30 days after sending, pairings 90 days after creation. The full schedule is in the privacy policy.
/api/cron/cleanupRuns the retention sweep immediately and returns the counts deleted. Intended for the daily scheduled job. Same retention rules as the dashboard’s messages list.
x-admin-secret header
Node SDK
Zero dependencies. Pairing, polling, verification, types. On npm as @muselovin/sdk.
$ npm install @muselovin/sdk
import { MuseLovin } from "@muselovin/sdk";
const ml = new MuseLovin({ apiKey: process.env.ML_API_KEY! });
const { code, sentence } = await ml.createPairing();
const agent = await ml.waitForRedeem(code);
const { valid } = await ml.verifyToken(agent.token);Get building.
Keys are free during the beta and take under a minute. Questions? Talk to us.