Last reviewed: 2026-07-15

Direct answer

Verify authorization before fallback routing with three separate checks: a real-key success request, an intentionally invalid-key request, and a valid-key request missing one required body field. In a bounded CometAPI validation with eight contract requests plus one model-catalog preflight, the real-key Responses and non-streaming Chat requests returned usable 200 responses; the invalid credential returned 401; and missing messages or input returned 400 with code=invalid_request. These results prove that the tested client can distinguish success, authentication failure, and request-shape failure. They do not prove uptime, latency, quota, or production readiness.

Keep endpoint families separate. Chat Completions uses messages and returns a chat.completion object. Responses uses input and returned a response object with status completed. A fallback client that sends the right bearer token to the wrong endpoint shape can still fail before model work begins.

Who this is for

This guide is for engineers responsible for gateway configuration, fallback promotion, secret injection, and incident reproduction. Run the checks from the same network and client stack used by the intended route, but keep the prompt non-sensitive and the request count bounded.

Key takeaways

  • The tested API base was https://api.cometapi.com/v1 with bearer-token authorization.
  • Responses with gpt-5-nano-2025-08-07 returned HTTP 200, object response, status completed, and usable content.
  • Non-streaming Chat Completions with gpt-4.1-nano returned HTTP 200, object chat.completion, finish reason stop, and usable content.
  • An intentionally invalid bearer token returned HTTP 401 with error keys code, message, and type.
  • A valid-key request missing messages or input returned HTTP 400 with code, message, param, and type; the observed code was invalid_request.
  • Do not include a real key, request ID, full prompt, full response, or commercial data in shared validation notes.

These point-in-time observations are backed by the sanitized eight-case contract evidence artifact , not inferred from HTTP status alone. The artifact also records the one-request ceiling deviation caused by counting the authenticated model-catalog preflight separately.

Contract details to verify

Contract areaValue or assertionEvidence
API basehttps://api.cometapi.com/v1CometAPI docs
Endpoint paths/chat/completions and /responses use different body contractsChat reference and Responses reference
Authorization headerAuthorization: Bearer ${COMETAPI_KEY} from a secret sourceOfficial references above
Required fieldsChat requires messages; Responses requires input; both require a modelEndpoint references above
Success contractRequire the endpoint-specific object, terminal state, and usable contentSanitized run
Controlled errorsInvalid bearer: 401; omitted required field: 400 in this runSanitized run; exact message wording is not asserted
StreamingEnvelope completion is insufficient without contentSanitized negative sample; streaming promotion remains held
Model IDsRecheck /v1/models before executionModel catalog and sanitized run preflight; future availability is not asserted
Rate limits and billingNot asserted; verify in the current account and product documentationOutside this authorization test

Run the success check

Set the key without printing it, then run one minimal Chat request:

curl --fail-with-body --silent --show-error \
  https://api.cometapi.com/v1/chat/completions \
  -H "Authorization: Bearer ${COMETAPI_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-4.1-nano",
    "messages": [{"role": "user", "content": "Reply exactly: OK"}],
    "max_completion_tokens": 64
  }'

The minimum pass is not merely HTTP 200. Assert the top-level object, one choice, assistant content, and a terminal finish reason. The sanitized observed record was:

{
  "endpoint_family": "chat_completions",
  "http_status": 200,
  "object": "chat.completion",
  "finish_reason": "stop",
  "content_assertion": "passed"
}

For a Responses route, change both the path and body contract:

curl --fail-with-body --silent --show-error \
  https://api.cometapi.com/v1/responses \
  -H "Authorization: Bearer ${COMETAPI_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-5-nano-2025-08-07",
    "input": "Reply exactly: OK",
    "max_output_tokens": 64
  }'

The observed Responses contract was HTTP 200, object response, status completed, with the content assertion passing.

Run the invalid-authorization check

Use a fixed invalid value, never a modified copy of the real credential:

curl --silent --show-error \
  https://api.cometapi.com/v1/chat/completions \
  -H 'Authorization: Bearer intentionally-invalid' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-5-nano-2025-08-07",
    "messages": [{"role": "user", "content": "Reply exactly: OK"}],
    "max_completion_tokens": 8
  }'

The expected and observed classification is HTTP 401 with a parseable error object. Assert the presence of code, message, and type; do not assert the exact human-readable message because wording can change.

{
  "http_status": 401,
  "error_fields": ["code", "message", "type"],
  "fallback_decision": "hold"
}

Separate authentication from request-shape errors

After the 401 check, restore the real secret source and deliberately omit messages:

curl --silent --show-error \
  https://api.cometapi.com/v1/chat/completions \
  -H "Authorization: Bearer ${COMETAPI_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{"model": "gpt-5-nano-2025-08-07"}'

The corresponding Responses negative test omits input. Both observed requests returned HTTP 400, included code, message, param, and type, and used code=invalid_request. That is evidence the credential was accepted far enough for request validation and that the client can distinguish malformed input from failed authorization.

Authorization assertion table

CheckExpectedObservedRoute decision
Chat success200 plus usable chat contentPassedContinue contract checks
Responses success200, completed response, usable contentPassedContinue contract checks
Invalid bearer token401 and structured errorPassedHold; fix credential source
Missing messages400, invalid_request, paramPassedHold; fix Chat body
Missing input400, invalid_request, paramPassedHold; fix Responses body

Streaming boundary

Do not infer streaming readiness from the non-streaming checks. Two separate Chat SSE probes returned HTTP 200, three chunks, and [DONE], yet produced no content and finished with length at a 64-token cap. That is a negative content sample. Keep streaming promotion disabled until a later bounded run returns usable content and passes parser assertions.

Failure modes and boundaries

  • Stop if the runtime reads a key from an unexpected environment, file, or account scope.
  • Do not retry a 401 as though it were a provider outage; repair authorization first.
  • Do not treat a 400 missing-field result as model unavailability.
  • Do not log the bearer token, full prompt, full output, or request identifiers.
  • Do not use these calls to claim price, balance, quota, latency, uptime, or universal model behavior.

For response-field assertions, use How to Use Response Contract Evidence to Harden LLM API Failover . Before promotion, complete Build a CometAPI Fallback Evidence Checklist .

Sources checked

Reader next step

Compare CometAPI models , then create or review the API key used by the controlled client.

FAQ

Should fallback trigger on a 401?

No. A 401 is an authorization boundary, not evidence that another model route is healthy. Hold the route and fix the credential source.

Can the same request body test both endpoint families?

No. Chat requires messages; Responses requires input. Test and assert them separately.