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
- 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>')
- Create a token in the admin API-keys UI if none exists
- 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
- Always send 'Authorization: Bearer <token>' on /v1/chat; browser sessions do not count
- Smoke-test the token with a trivial request when setting up n8n/Make integrations
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
- Admin only
- API token is not scoped for chat
- HTTP ' + r.status
- Username already taken
- Invalid credentials
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/be07a60aaa15a510.
Report an issue: GitHub.