Generic JSON API
The answer to "I want to use this with that random API our team uses." You describe which JSON paths in the request and response carry human text, and AdaptiveAPI handles the round trip. No code changes on either end.
What this is for
The generic adapter handles any HTTP+JSON service. If it speaks JSON over HTTP, it works. Common cases:
- A non-OpenAI LLM provider: Cohere, Mistral, your own vLLM, an in-house model.
- A search backend: ElasticSearch, Algolia, Typesense, an internal search service.
- A CMS or knowledge base API.
- A help-desk webhook payload that needs to land in the agent's language.
- An internal microservice you do not want to teach about i18n.
- A vendor API your team integrates with that does not have a typed surface.
The shape of a generic route
A generic route definition has four blocks: upstream, request, response, and direction.
{
"upstream": {
"urlTemplate": "https://api.cohere.com/v1/chat",
"method": "POST",
"additionalHeaders": { "X-Client-Name": "my-app" }
},
"request": {
"translateJsonPaths": [
"$.message",
"$.chat_history[*].message",
"$.tools[*].description"
]
},
"response": {
"streaming": "sse",
"eventPath": "$.text",
"finalPaths": ["$.text", "$.generations[*].text"]
},
"direction": "bidirectional"
}
upstream
urlTemplate. The full upstream URL.{path}in the template is replaced with whatever follows the route token in the inbound URL.method.POST,GET,PUT,PATCH,DELETE.additionalHeaders. Static headers added to every upstream call. Authorization is forwarded from the inbound request, untouched.
request
translateJsonPaths. JSONPath expressions pointing at the human-text leaves to translate before forwarding. Identifiers, IDs, URLs, enum values are not in this list.passThroughPaths. Optional. Paths that must be preserved verbatim even if they overlap with translate paths.
response
streaming.nonefor plain JSON,ssefor Server-Sent Events,ndjsonfor line-delimited JSON.eventPath. For streaming responses, the JSONPath inside each event payload to translate progressively (sentence-boundary buffered).finalPaths. JSONPath list of fields to translate in the final non-streaming response, or in the terminal SSE event.
direction
bidirectional. Translate request and response.request-only. Only translate the request. Useful when the upstream returns identifiers or codes you do not want translated.response-only. Only translate the response.off. Pass through. The token gate and audit log still apply.
Calling a generic route
The route token slots in after the /generic/ prefix. Append
the upstream path if your urlTemplate uses {path}.
curl -X POST "https://adaptiveapi.example.com/generic/rt_yourtenant_xxxxx/" \
-H "Authorization: Bearer your-cohere-key" \
-H "X-AdaptiveApi-Target-Lang: de" \
-H "Content-Type: application/json" \
-d '{
"message": "What is a hashmap?",
"model": "command-r"
}'
The request goes out to the upstream URL with the listed paths translated
to the source language. The response comes back with finalPaths
translated into the target language. SSE responses are buffered at sentence
boundaries and re-emitted as synthetic deltas, the same way the OpenAI
surface streams.
Worked examples
Custom search API
Suppose you run an internal search endpoint at
https://search.internal/api/query. It takes a query string and
returns ranked snippets. You want users to type in any language and get
results translated back.
{
"upstream": {
"urlTemplate": "https://search.internal/api/query",
"method": "POST"
},
"request": {
"translateJsonPaths": ["$.query"]
},
"response": {
"streaming": "none",
"finalPaths": [
"$.results[*].title",
"$.results[*].snippet"
]
},
"direction": "bidirectional"
}
The user's German query is translated to English before the search engine
sees it. Each result's title and snippet come back translated to German.
results[*].url and results[*].id are not in the
list, so they survive verbatim.
Streaming chat API
Same shape, but the upstream emits SSE. The eventPath tells
AdaptiveAPI which field of each event payload to translate progressively.
{
"upstream": {
"urlTemplate": "https://your-llm.example/chat/stream",
"method": "POST"
},
"request": {
"translateJsonPaths": ["$.prompt", "$.context[*].text"]
},
"response": {
"streaming": "sse",
"eventPath": "$.delta",
"finalPaths": ["$.final.text"]
},
"direction": "bidirectional"
}
Help-desk webhook ingestion
Inbound webhook from a help-desk vendor. The agent reads German. The body arrives in whatever the customer wrote.
{
"upstream": {
"urlTemplate": "https://your-helpdesk.internal/webhooks/inbound",
"method": "POST"
},
"request": {
"translateJsonPaths": [
"$.subject",
"$.body",
"$.thread[*].body"
]
},
"response": { "streaming": "none" },
"direction": "request-only"
}
What survives verbatim
Anything not listed in translateJsonPaths, eventPath,
or finalPaths passes through untouched. That includes:
- IDs, UUIDs, slugs, codes, enum values.
- URLs, file paths, content hashes.
- Numeric scores, booleans, timestamps.
- Headers (other than
X-AdaptiveApi-*, which are stripped). - Status codes, content types, and SSE framing.
That makes the generic adapter safe to point at APIs whose responses mix human text with machine fields, which is most of them.
Combining with style rules and glossaries
A generic route can bind to a style rule and a glossary the same way the typed routes do. The DeepL v3 style rule applies to translation calls made from the route, including locale-aware formatting (number formats, date formats, formality). See Style rules & customization for the locale-formatting story.
Tip. Start with
direction: "off"when you first wire up an unfamiliar API. AdaptiveAPI will route and audit requests without touching the bodies, so you can verify the URL and auth flow before turning translation on.