Consuming the API¶
Once a project has an endpoint and a key, your applications talk to it through the OpenAI-compatible chat completions API. This is the only protocol customer applications use — if your code already talks to OpenAI, it already talks to Adapta.
The three things you need¶
| Thing | Where it comes from | Used as |
|---|---|---|
| Base URL | Your server, e.g. http://your-server:8000/v1 |
OpenAI client base_url |
| Endpoint slug | The Endpoint tab in the console | the model field |
Scoped key (adp_…) |
The Keys tab (shown once) | the api_key |
Python (OpenAI SDK)¶
from openai import OpenAI
client = OpenAI(
base_url="http://your-server:8000/v1",
api_key="adp_xxxx…", # scoped to one project endpoint
)
resp = client.chat.completions.create(
model="support-kb-a1b2c3d4", # your endpoint slug (from the console)
messages=[{"role": "user", "content": "What is our refund window?"}],
)
print(resp.choices[0].message.content)
curl¶
curl http://your-server:8000/v1/chat/completions \
-H "Authorization: Bearer adp_xxxx…" \
-H "Content-Type: application/json" \
-d '{
"model": "support-kb-a1b2c3d4",
"messages": [{"role": "user", "content": "What is our refund window?"}]
}'
What's different from vanilla OpenAI¶
- The key picks the endpoint, not the
modelfield. Eachadp_key is bound to exactly one endpoint. Themodelslug you pass must match the key's endpoint — a mismatched slug is rejected (403). This means a key can never reach an endpoint it wasn't issued for. - Answers carry citations when the project has documents. If the project
has indexed documents (a Knowledge project, or a finetune project that also
uploaded documents), the response is grounded in them and includes the source
chunks it used. Each citation is
{index, source, score, score_kind, text, file_id, page, ocr, confidence}:textis the cited passage,pageis the 1-based page (nullfor formats without pages), and for scanned documentsocristrueandconfidenceis the mean OCR confidence in 0–1 (nullotherwise). The index matches the[N]markers in the answer. - Follow-up questions are understood. On a project with documents, once the
conversation has two or more user turns the server first asks the model to
rewrite your last question as a standalone one ("and how many days for that?"
becomes "How many vacation days do employees get?"), then retrieves on that
rewrite and your original text. It costs one short extra generation (at
most 40 tokens) only on those follow-up turns; first questions are unaffected.
Those tokens are counted in
usage. If the rewrite fails or times out, the server quietly retrieves on your last message alone. Send"adapta": {"condense": false}to turn it off for a request. - Usage is metered. Every response includes
prompt_tokens,completion_tokens, andtotal_tokens, and is rolled up per day (visible in the console's Usage tab). - Finetune endpoints serve base + adapter. A finetune project's endpoint applies its LoRA adapter on top of the base model transparently — the request shape is identical. (Creating one requires an imported adapter that has passed the CPU eval gate.) If that project also indexed documents, retrieval and the adapter compose in the same call (see Knowledge + behavior together).
Images (vision endpoints)¶
An endpoint whose project was created on a vision base model accepts the
standard OpenAI image content-parts — the image inline as a base64 data: URL:
import base64
with open("invoice.png", "rb") as f:
data_url = "data:image/png;base64," + base64.b64encode(f.read()).decode()
resp = client.chat.completions.create(
model="invoice-reader-a1b2c3d4",
messages=[{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": data_url}},
{"type": "text", "text": "Extract vendor, date and total as JSON."},
]}],
)
Rules (v1, all violations come back as typed 4xx errors, never a crash):
- Inline
data:URLs only — the server never fetches remote image URLs. - png, jpeg or webp; ≤ 10 MB and ≤ 8192 px per image; ≤ 4 images per request.
- Requests with images are non-streaming (
streammust be false) and skip document retrieval — text-only requests on the same endpoint still answer from indexed documents with citations. - Sending an image to a text endpoint returns a clear
400— create the project on a vision base instead.
JSON mode (response_format)¶
Any endpoint can be forced to emit valid JSON, OpenAI-style. The output is constrained at decode time (a llama.cpp grammar), so it parses every time — no adapter needed for the shape:
resp = client.chat.completions.create(
model="your-endpoint-slug",
messages=[{"role": "user", "content": "Extract name and total from: ACME invoice, $42.10"}],
response_format={"type": "json_object"},
)
{"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} constrains the output to
that schema; an invalid schema is a 422. Works with streaming. {"type": "text"} (the default) is
unconstrained.
Streaming¶
Set "stream": true (or stream=True in the SDK) to receive tokens as
server-sent events, the same as the OpenAI streaming protocol. The final chunk
carries the usage totals, and — when the project has indexed documents —
citations in the same shape as the non-streaming response (each entry's
score_kind says whether score came from the reranker or from vector
similarity alone). (Not available for requests carrying images — see above.)
Errors¶
Errors come back in a consistent envelope with a correlation_id:
If you need to report a problem, the correlation_id lets an operator find the
exact request in the server logs. No internal details (stack traces, library
errors) are ever exposed in the response.
The full request/response schema for every endpoint is in the API reference, generated from the live OpenAPI spec.