Custom Endpoints & Headers¶
Beyond Direct Provider Access¶
By default, majordomo-llm sends requests directly to each provider's API (e.g., api.openai.com, api.anthropic.com). But many production setups need to route requests through an intermediary:
- API gateways like majordomo-gateway for centralized logging, rate limiting, and cost tracking
- Corporate proxies that enforce security policies or audit requirements
- Self-hosted models served behind an OpenAI-compatible API
- Regional endpoints for data residency compliance
Custom endpoints let you point any provider at a different URL and attach custom HTTP headers to every request.
Two Levels of Headers¶
majordomo-llm supports headers at two levels:
Instance-level: default_headers¶
Set once at construction time, sent with every request from that instance. Use these for stable identifiers that don't change between calls.
llm = get_llm_instance(
"anthropic", "claude-sonnet-4-20250514",
base_url="https://gateway.example.com",
default_headers={
"X-Majordomo-Key": "mdm_key_here",
"X-Majordomo-Feature": "search",
"X-Majordomo-User-Id": "user_abc",
},
)
Per-request: extra_headers¶
Set on individual API calls. Merged with instance headers on each request, with per-request values winning on conflict.
response = await llm.get_response(
"Summarize this document",
extra_headers={"X-Request-Id": "req_123"},
)
In this example, the request is sent with all four headers: the three from default_headers plus X-Request-Id from extra_headers.
How It Works Per Provider¶
Each provider SDK handles headers differently. majordomo-llm maps base_url, default_headers, and extra_headers to the right SDK mechanism automatically:
| Provider | Instance headers | Per-request headers |
|---|---|---|
| OpenAI | default_headers= on AsyncOpenAI constructor |
extra_headers= on API calls |
| Anthropic | default_headers= on AsyncAnthropic constructor |
extra_headers= on API calls |
| DeepSeek | default_headers= on AsyncOpenAI constructor |
extra_headers= on API calls |
| Gemini | HttpOptions(headers=) on genai.Client |
HttpOptions(headers=) in GenerateContentConfig |
| Cohere | Merged into request_options per call |
request_options with additional_headers |
You don't need to know these details. The same default_headers and extra_headers dictionaries work identically across all providers.
Composability¶
Custom endpoints compose naturally with every other feature:
- Cascade: Pass
base_urlanddefault_headerstoLLMCascadeto route all providers through the same gateway - Logging:
LoggingLLMpassesextra_headersthrough to the wrapped LLM - Streaming:
extra_headersworks onget_response_stream()calls - Structured outputs:
extra_headersworks onget_structured_json_response()calls
Next Steps¶
See the Proxy Routing recipe for practical examples including gateway integration, per-request metadata, and cascade routing.