M Motionworks Population Intelligence

API error codes

Every error response from the Motionworks API uses the same JSON envelope and carries a docs_url pointing at the section below that describes the specific error.code. The X-Request-Id response header always matches the request_id field in the body — include it when filing support tickets.

This page documents the auth-related error codes shipped with the v2 API-key flow. See the API reference for the canonical list of stable codes and the authentication & quotas page for the access-tier model.

AMBIGUOUS_AUTH

HTTP 400 Bad Request

Returned when a single request includes both an X-API-Key header and an Authorization: Bearer header. The router rejects rather than picking one silently, because the two auth modes carry different identities and billing contexts.

Example response

{
  "error": {
    "code": "AMBIGUOUS_AUTH",
    "message": "Use either X-API-Key or Authorization: Bearer, not both.",
    "status": 400,
    "request_id": "req_abc123def456",
    "docs_url": "https://mworks.com/developers/docs#ambiguous-auth",
    "context": {
      "present_headers": ["X-API-Key", "Authorization"],
      "choose_one": ["X-API-Key", "Authorization: Bearer <jwt>"]
    }
  }
}

Reproduce

curl -i https://api2.mworks.com/v2/markets \
  -H "X-API-Key: $MW_API_KEY" \
  -H "Authorization: Bearer $MW_JWT"

Remediation

Pick the auth mode appropriate to your call and remove the other header:

  • X-API-Key — server-to-server data calls against product endpoints (Popcast, Placecast, Pathcast, Viewcast, platform). Recommended for backend integrations.
  • Authorization: Bearer <jwt> — account-management endpoints under /v2/account/* and /v2/billing/*. Used by the in-app portal flow at app2.mworks.com.

Related

SCOPE_NOT_SUPPORTED

HTTP 400 Bad Request

Returned when an API key's scope attribute is anything other than 'read'. The v2 MVP only supports read scope; this gate is the no-op precursor to future scope enforcement (write, admin) and rejects unknown scopes loudly rather than silently treating them as read.

Example response

{
  "error": {
    "code": "SCOPE_NOT_SUPPORTED",
    "message": "API key scope is not supported.",
    "status": 400,
    "request_id": "req_def456abc789",
    "docs_url": "https://mworks.com/developers/docs#scope-not-supported",
    "context": {
      "scope": "write",
      "supported": ["read"]
    }
  }
}

Reproduce

The error surfaces when a key minted with a non-read scope is used against any v2 endpoint:

curl -i https://api2.mworks.com/v2/markets \
  -H "X-API-Key: mwk_live_write_..."

Remediation

Mint a new key with scope: 'read' from the portal at app2.mworks.com and replace the offending key in your client configuration. There is no way to "upgrade" an existing key's scope — keys are immutable. Future MVP releases will add write and admin scopes; this page will be updated then.

Related

ORIGIN_NOT_ALLOWED

HTTP 403 Forbidden

Returned when an API key has a non-null allowed_origins list configured and the request's Origin header doesn't satisfy the per-key allowlist policy. See ADR-25 in api-mworks-com for the full policy definition.

Example response

{
  "error": {
    "code": "ORIGIN_NOT_ALLOWED",
    "message": "Request Origin is not permitted for this API key.",
    "status": 403,
    "request_id": "req_789xyz012abc",
    "docs_url": "https://mworks.com/developers/docs#origin-not-allowed",
    "context": {
      "reason": "origin_not_allowed",
      "origin": "https://other.example"
    }
  }
}

Reason codes

The context.reason field disambiguates the three rejection paths:

ReasonCondition
origin_required The key has a non-empty allowed_origins list, but the request arrived without an Origin header (typical for server-to-server callers).
origin_not_allowed The request's Origin header was present but didn't match any entry in the key's allowlist.
origin_disabled The key's allowed_origins is set to an empty array ([]) — browser use is explicitly disabled for this key.

Reproduce

curl -i https://api2.mworks.com/v2/markets \
  -H "X-API-Key: $MW_API_KEY" \
  -H "Origin: https://other.example"

Remediation

  • Server-to-server caller hitting origin_required — mint a separate key with allowed_origins = NULL (the default) for backend use, or remove the allowlist from the existing key in the portal.
  • Browser caller hitting origin_not_allowed — add your deployed origin (exact match, scheme + host + port) to the key's allowed_origins list at app2.mworks.com.
  • Browser caller hitting origin_disabled — the key is server-to-server only. Either mint a new key with a non-empty allowlist or route the call through your backend.

Related