Conventions
These rules hold across the whole /v1 API. The reference gives the details of each operation.
Base URL
https://api.missived.com/v1
On a self-hosted server, use your server's API URL. With the bundled proxy, the API sits under your site's /api path, for example https://chat.example.com/api/v1. The app's own reference at /developers shows the right URL for the server you're on.
Requests and responses
- Bodies are JSON (
Content-Type: application/json), except file uploads, which aremultipart/form-data. - Keys are snake_case:
channel_id,created_at,next_cursor. - Ids are strings. Treat them as opaque; don't parse them or assume a length.
- Times are ISO 8601 in UTC, such as
2026-10-14T10:26:40.000Z. - A value that is absent is
null. Documented keys are always present. - Ignore fields you don't know. New fields can appear at any time within v1.
Lists and paging
Every list answers the same shape:
{ "data": [ … ], "next_cursor": "…" }
limitsets the page size (1 to 100 on most lists; the reference gives each list's range).- Pass
next_cursorback ascursorto get the next page. When it isnull, there are no more pages. - Cursors are opaque. Never build or edit one; an invalid one answers
400 invalid_cursor.
Messages come newest first. To follow a channel, ask for order=oldest: each page gives a next_cursor that you keep and pass back next time to get only what is new. An empty page still gives you a cursor to resume from.
Errors
Errors have a status code and a body like this:
{ "error": { "code": "insufficient_scope", "message": "This token doesn't have the messages:write scope." } }
code is stable and machine-readable; message is a sentence for a person and may change. Common codes:
| Status | Codes |
|---|---|
400 |
invalid_request, invalid_cursor, invalid_embeds, embeds_not_allowed, invalid_components, components_not_allowed |
401 |
unauthenticated, token_invalid, token_revoked, token_expired, account_suspended |
403 |
insufficient_scope, org_not_allowed, forbidden |
404 |
not_found |
409 |
conflict, idempotency_in_progress |
413 |
payload_too_large |
422 |
idempotency_key_reused |
429 |
rate_limited |
500, 503 |
internal_error, unavailable |
New codes can appear for new situations, so handle unknown codes by their status.
A thing in another org, or one this token can't see, always answers 404 not_found. Missived doesn't confirm that something exists before it checks whether you may see it.
The integration management routes (incoming webhooks, audit-log destinations, feeds) are older and answer { "error": "A sentence." } instead; for a token they add a code next to it. Their reference entries say so.
Caching with ETags
Every successful GET answers with an ETag header. Send it back as If-None-Match and, if nothing changed, you get 304 Not Modified with no body:
curl -i -H "Authorization: Bearer $MISSIVED_TOKEN" \
-H 'If-None-Match: "<etag from last time>"' \
https://api.missived.com/v1/orgs/<orgId>/channels
Idempotency keys
POSTs that create messages, channels and tasks accept an Idempotency-Key header, and so do interaction follow-ups. Use a unique value per thing you mean to create, such as a UUID or your own job id.
- The same key from the same caller within 24 hours returns the first result, with an
Idempotent-Replayed: trueheader, instead of creating a second one. - The same key with a different body or on a different route answers
422 idempotency_key_reused. - If the first request is still running, a second one answers
409 idempotency_in_progress. Wait and retry.
Missived keeps only the status and the created resource's id for a key, never the body. When you retry a job or handle an event that can arrive twice, reuse the same key: a fresh key can't recognise a repeat.
Rate limits
- 300 requests a minute per token. Each response reports the budget in
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Reset. - Over the limit, you get
429 rate_limitedwith aRetry-Afterheader (seconds). Wait that long, then retry. - Posting, editing and reacting also spend the chat budget every person has, so a script can't flood a channel. A bot spends its own budget, not its creator's.
- Some features have their own limits, given on their pages: incoming webhooks, the gateway, slash commands and the MCP server.
Versioning
- Within v1, changes are additive only: new operations, new optional inputs, new response fields, new error codes for new situations, and new values in fields documented as open.
- Breaking changes ship as
/v2: removing or renaming an operation, field or input, changing a type, making an input required, or changing what a scope allows./v1keeps working alongside. - Deprecation: something due to be retired is marked
deprecatedin the reference, answers with aDeprecationheader (and aSunsetheader once a date is set), and is announced at least 90 days before it stops working. - The document's version (
info.version, now shown at the top of the reference) goes up a minor number for additions and a patch number for wording.