The Mouve API is in active development and not yet live. Follow the changelog for the launch announcement.

Mouve Developers

Errors

RFC 9457 problem+json responses, the frozen error-code registry, and the 401/403 discipline.

Every error from /public/v1 is an RFC 9457 problem document:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
{
  "type": "https://developers.mouve.it/errors/insufficient-scope",
  "title": "Insufficient scope",
  "status": 403,
  "code": "INSUFFICIENT_SCOPE",
  "detail": "This request requires the posts.write scope.",
  "request_id": "req_8f3a1c2b9d4e"
}
  • Match on code — stable, UPPER_SNAKE, from the registry below. detail is human wording and may change; code never does.
  • request_id identifies the exact request in Mouve's logs — include it in any support report. It is also on every success response as the X-Request-Id header.
  • VALIDATION_FAILED adds an errors array of {"field": "...", "message": "..."} items.
  • 429 problems add scope, window, limit, and retry_after_seconds members plus a Retry-After header — see rate limits.

Status discipline

The status code alone tells you the category of your next move:

StatusMeaningYour move
401The token itself is invalid, expired, or revokedRefresh (OAuth) or obtain a new token; if that fails, re-authorize
403Token is fine; this action is not permittedDo not retry, do not refresh — fix scopes or respect the block
409Same idempotency key still in flightRetry after Retry-After
422Request understood, semantically rejectedFix the request; retrying unchanged will fail again
429Over a rate limitBack off per Retry-After
5xxMouve-side faultRetry with backoff and the same Idempotency-Key

Registry

Append-only: codes are never removed, renamed, or moved to another status. Additions are announced in the changelog.

StatusCodeWhen
400VALIDATION_FAILEDA field is missing, malformed, or out of range (includes missing audience)
400INVALID_CURSORCursor is malformed, expired in format, or minted by a different query
400INVALID_IDEMPOTENCY_KEYIdempotency-Key header fails the format rules
401UNAUTHENTICATEDNo usable credential on the request
401TOKEN_EXPIREDAccess token past its lifetime
401TOKEN_REVOKEDGrant disconnected or token revoked — do not retry
403INSUFFICIENT_SCOPEToken lacks a required scope
403VENUE_NOT_VERIFIEDThe venue has not proven it controls its domain yet (verification tier below t1)
403APPROVAL_REQUIREDThe change needs the venue owner to approve it; the response carries approval_url, do not retry
403TOKEN_NOT_PERMITTEDEndpoint is not available to API tokens at all
403FORBIDDENPermitted scope, but this specific resource/action is not allowed
403ACCOUNT_SUSPENDEDThe acting user's account is suspended
403ONBOARDING_REQUIREDThe acting user has not completed onboarding
403CLIENT_DISABLEDThe app the token belongs to is disabled or taken down
404NOT_FOUNDResource absent — or not visible to the acting user
409IDEMPOTENCY_IN_FLIGHTSame key currently processing; retry shortly
409SLOT_UNAVAILABLEThe slot was taken (or is closed) by the time the booking was made; pick another slot
409CHANGESET_STALEThe changeset was edited after the approval hash was computed; review it again
409CHANGESET_OPENAnother changeset of the venue is already open (the owner's, or another sign-in's); wait until it is approved, rejected or expired
409CONFLICTThe request conflicts with the current state of the resource; read it again before retrying
410ENDPOINT_RETIREDEndpoint passed its published sunset date
413PAYLOAD_TOO_LARGEBody or upload exceeds the size limit
422IDEMPOTENCY_BODY_MISMATCHSame key, different request body
422OUTSIDE_HOURSThe booking falls outside the venue opening hours
422AUDIENCE_UNAVAILABLEe.g. audience: "everyone" on a private-profile account
422MEDIA_NOT_FOUNDA media_ids entry does not exist or is not yours
422MEDIA_ALREADY_ATTACHEDMedia id already used by another post
422MEDIA_URL_INVALIDSource URL is not fetchable HTTPS
422MEDIA_URL_BLOCKEDSource URL is not allowed
422MEDIA_FETCH_FAILEDSource URL did not yield a usable image
422MEDIA_TOO_LARGEImage exceeds 10 MB
422MEDIA_UNSUPPORTED_TYPENot JPEG, PNG, WebP, or GIF
422MEDIA_VIDEO_UNSUPPORTEDVideo is not supported in v1
429RATE_LIMITEDPer-minute limit exceeded
429USAGE_LIMIT_EXCEEDEDDaily write cap exceeded
429MEDIA_QUOTA_EXCEEDEDRolling media quota exceeded
500INTERNALUnexpected Mouve-side error
503UNAVAILABLETemporarily unable to serve; retry with backoff
503VENUE_AGENT_WRITES_DISABLEDWrites made with an OAuth or API credential are switched off (venue freeze or the org-wide kill switch); session writes still work

One deliberate ambiguity: 404 NOT_FOUND is returned both for resources that do not exist and for resources the acting user may not see — the API never confirms the existence of content you cannot access.