Skip to content

Authentication

Every request to /v1 carries a bearer token:

Authorization: Bearer mls_live_3f9ac2e8b71d4c5f9e2a7b6c1d0e

There are three kinds of token. Two of them are API keys, the third is a browser session for the widget.

Prefix Kind Can
mls_live_… Partner key Everything for your partner: all workspaces, the webhook, embed sessions
mls_live_… (workspace-scoped) Workspace key Only that one workspace. Minted for a customer, a mobile app or an MCP client
mle_… Embed session The widget’s short-lived, workspace-scoped token. Only /v1/embed/*

Partner keys and workspace keys share the mls_live_ prefix. The scope is decided when the key is created, not by the prefix.

Keys are stored hashed (SHA-256) and shown exactly once, at creation. Store them in a secret manager, never in a browser or a mobile app binary.

MissLess issues your partner key when your partner account is set up. Use it from your backend only. To rotate a partner key, ask MissLess for a new one, switch your backend over, then ask for the old one to be revoked.

You can mint keys that only reach one workspace. They are the recommended credential for end users: give one to a customer’s MCP client or mobile app, and a leak can only touch that customer’s accounts.

Terminal window
curl -X POST https://social.missless.tel/v1/workspaces/ws7k2m9p4q1r8t3/keys \
-H "Authorization: Bearer $MISSLESS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "label": "Claude Code on Nova laptop" }'

Response 201, the only time key is returned:

{ "id": "key4d6f8h2j4l6n", "key": "mls_live_8a1d4f7c2e9b6a3d5f0c8e1b4a7d", "prefix": "mls_live_8a1d", "label": "Claude Code on Nova laptop" }

List and revoke:

Terminal window
curl https://social.missless.tel/v1/workspaces/ws7k2m9p4q1r8t3/keys \
-H "Authorization: Bearer $MISSLESS_API_KEY"
curl -X DELETE https://social.missless.tel/v1/workspaces/ws7k2m9p4q1r8t3/keys/key4d6f8h2j4l6n \
-H "Authorization: Bearer $MISSLESS_API_KEY"

The list returns { id, prefix, label, last_used_at, created } per key. prefix is enough to tell keys apart in a UI.

Rotation is create-switch-delete: mint a new key, move the client over, delete the old one. A deleted key stops working immediately.

An embed session is minted server-side with POST /embed-sessions using your partner key. It expires (default 3600 seconds) and only works against /v1/embed/*. It is safe to put in the browser because it cannot reach anything outside its workspace or outlive its expiry. See Embed sessions.

Call Partner key Workspace key Embed session
POST /workspaces, GET /workspaces yes no no
GET, PATCH, DELETE /workspaces/:id yes own workspace only no
/workspaces/:id/keys yes no no
/workspaces/:id/connect-links, /workspaces/:id/accounts yes own workspace only no
/accounts/:id, /media, /posts, /conversations yes objects in own workspace only no
/webhook, /webhook/test, /events yes no no
POST /embed-sessions yes no no
/embed/* no no yes
/mcp yes, with X-MissLess-Workspace yes no

A workspace key gets forbidden (403) on anything outside its workspace, and not_found (404) for objects that belong to another workspace.

  • 300 requests per minute per key.
  • 60 requests per minute per IP address on unauthenticated endpoints (the connect page and the OAuth callback).

Over the limit you get 429 with a Retry-After header (seconds). Back off for that long, then retry. Instagram has its own publishing limit of 100 posts per account per 24 hours, which surfaces as a network_error. See Rate limits.

Every error has the same shape:

{ "error": { "code": "validation_error", "message": "caption is required", "field": "caption" } }
Code HTTP When
unauthorized 401 Missing, malformed, revoked or expired token
forbidden 403 The token is valid but cannot reach this workspace or resource
not_found 404 No such object in your scope
validation_error 400 A field is missing or invalid; field names it
unsupported 400 The network cannot do what you asked, for example text-only on Instagram
conflict 409 The object is in a state that does not allow the action, for example patching a published post
account_disconnected 409 The target account is expired, revoked or in error; reconnect it
rate_limited 429 Over the limit; honour Retry-After
network_error 502 Meta refused or failed the request; details carries Meta’s error

field is present on validation_error only. details is present on network_error only. Full list with handling advice in Errors.