odysseus-dev/odysseus · error · HTTPException

This endpoint requires an API token

Error message

This endpoint requires an API token

What it means

HTTP 403 from POST /v1/chat: the request carried no API token. The route checks request.state.api_token, which is set by API-token middleware; falsy means the Authorization header did not present a valid token (absent, malformed, or rejected upstream).

Source

Thrown at routes/webhook/webhook_routes.py:240

        if model:
            model_lower = model.lower()
            for prefix, prov in MODEL_PROVIDER_MAP.items():
                if model_lower.startswith(prefix):
                    return KNOWN_PROVIDERS[prov]
        return None

    class SyncChatRequest(BaseModel):
        message: str = Field(..., max_length=MAX_MESSAGE_LEN)
        model: Optional[str] = Field(None, max_length=200)
        session: Optional[str] = Field(None, max_length=100)
        api_key: Optional[str] = Field(None, max_length=256)
        base_url: Optional[str] = Field(None, max_length=MAX_URL_LEN)
        provider: Optional[str] = Field(None, max_length=50)

    @router.post("/v1/chat")
    async def sync_chat(request: Request, body: SyncChatRequest):
        if not getattr(request.state, "api_token", False):
            raise HTTPException(403, "This endpoint requires an API token")
        scopes = set(getattr(request.state, "api_token_scopes", []) or [])
        if "chat" not in scopes:
            raise HTTPException(403, "API token is not scoped for chat")
        token_owner = getattr(request.state, "api_token_owner", None)

        from core.models import ChatMessage
        from src.llm_core import llm_call_async
        from src.endpoint_resolver import build_chat_url, build_headers, build_models_url, normalize_base

        message = body.message.strip()
        if not message:
            raise HTTPException(400, "Message is required")

        session_id = body.session
        sess = None

        # --- Case 1: Resume an existing session ---
        if session_id and session_manager:

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Send the API token in the Authorization header exactly as the middleware expects (check the API-token auth middleware for scheme, e.g. 'Authorization: Bearer <token>')
  2. Create a token in the admin API-keys UI if none exists
  3. In n8n/Make, switch the node's auth type to 'Generic Credential / Header Auth' or Bearer and paste the token

Example fix

# before
curl -X POST http://host/api/webhooks/v1/chat -d '{"message":"hi"}'

# after
curl -X POST http://host/api/webhooks/v1/chat \
  -H 'Authorization: Bearer sk-...' \
  -H 'Content-Type: application/json' \
  -d '{"message":"hi"}'
Defensive patterns

Strategy: validation

Validate before calling

# before the call: ensure a token is configured
if not API_TOKEN:
    raise ConfigError("Create an API token in Admin and set API_TOKEN")

Try / catch

if resp.status_code == 403 and 'requires an API token' in detail:
    raise ConfigError('missing/invalid Authorization header for /v1/chat')

Prevention

When it happens

Trigger: Calling /v1/chat with no Authorization header; sending a session cookie but no API token (admin browser login does not satisfy this check); sending a malformed header the middleware drops without setting state.

Common situations: n8n/Make/Activepieces integration where the HTTP Request node was configured without the API-key auth preset; curl examples missing the header; assuming the admin UI session works for the sync endpoint.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/be07a60aaa15a510. Report an issue: GitHub.