Troubleshooting

Start by checking whether the request reached JoyToken, then decide whether the issue is authentication, policy, wallet, routing, provider, or client parsing.

Quick Checklist

CheckExpected
Base URLhttps://api-dev.joytokens.ai/openai/v1
Chat endpointPOST /chat/completions, full path /openai/v1/chat/completions
AuthAuthorization: Bearer $JOY_TOKEN_API_KEY
Content-Typeapplication/json
ModelStart with auto, then move to a concrete model_key
Messagesmessages must be non-empty
Request IDSend X-Request-ID to correlate gateway logs and Usage
WalletPersonal or organization wallet has balance
PolicyIP, tier, fixed model, and model blacklist allow the request

Status Codes

StatusCommon causeAction
400Invalid JSON, empty messages, or body over 8 MiBCompare against the Chat Completions example
401Missing API keyCheck the Authorization header
403Invalid key or policy rejectionCheck key status, IP, model, and tier
402Insufficient wallet balance or quota exceededTop up, switch billing account, or lower tier
404Endpoint or model does not existCheck URL and model key
405Wrong HTTP methodChat Completions must use POST
502Router, provider-adapter, or upstream provider failureCheck request ID, selected model, provider, and upstream error
503Downstream service unavailable, such as admin-bff not configured or gRPC unavailableRetry later or check service status
504Downstream timeoutReduce request complexity, enable streaming, or check provider status

Error Shape

Model call errors keep the OpenAI-compatible style:

Error response
1{
2 "error": {
3 "type": "policy_rejected",
4 "message": "requested tier is not allowed"
5 }
6}

The model list endpoint /api/v1/models uses the front-gateway response shape:

Models error
1{
2 "code": 50300,
3 "message": "admin-bff not available"
4}

Log Correlation

Server-side requests should always include a readable request ID:

Traceable request
$curl https://api-dev.joytokens.ai/openai/v1/chat/completions \
> -H "Authorization: Bearer $JOY_TOKEN_API_KEY" \
> -H "Content-Type: application/json" \
> -H "X-Request-ID: prod-chat-20260629-0001" \
> -d '{
> "model": "auto",
> "messages": [{ "role": "user", "content": "ping" }]
> }'

Then check in this order:

  1. api-gateway logs: whether the request arrived and whether key source is Bearer or X-API-Key.
  2. API key validation: valid, status, api_key_id, tier.
  3. Policy: IP, tier, fixed model, blacklist.
  4. Routing: whether selected_model was returned.
  5. Wallet: whether balance precheck and freeze succeeded.
  6. Provider: actual X-DAOE-Used-Model and X-DAOE-Used-Provider.
  7. Usage / Billing: whether usage was recorded and freeze was settled.

Common Issues

IssueExplanation
Works locally, fails with 403 in productionProduction egress IP is not in policy allowlist, or the production key has different tier/model policy
auto works, fixed model failsAPI key fixed model, model blacklist, or missing model in the model pool
Fixed model works, auto failsNo candidate model remains after policy/tier filtering, or router returned no selected_model
Streaming UI hangsClient does not parse SSE correctly, or renders the metadata event as assistant delta
No Usage recordProvider failed, stream usage was incomplete, billing calculate/record usage failed, or async settle is still pending
Wallet has balance but request failsCheck whether balance exists in the same tier as the selected tier

Minimal Reproduction

Start with the smallest request to rule out SDK and business-code issues:

Minimal request
$curl https://api-dev.joytokens.ai/openai/v1/chat/completions \
> -H "Authorization: Bearer $JOY_TOKEN_API_KEY" \
> -H "Content-Type: application/json" \
> -H "X-Request-ID: debug-minimal-001" \
> -d '{
> "model": "auto",
> "messages": [{ "role": "user", "content": "ping" }],
> "stream": false
> }'

If the minimal request works, add back tier, tools, streaming, long context, and fixed model one at a time.