Documentation / Reference / Application API
Your application talks to Pointsman; Pointsman authenticates its virtual key, applies its controls and calls an eligible model. You supply provider credentials to the gateway, not to every application. This page explains the application-facing HTTP contract with examples you can adapt after the quickstart.
The launch scope is Chat Completions. This is not support for every endpoint or field in another provider's API. Read the compatibility matrix for provider differences and explicit refusals. The examples here are illustrative; this documentation update did not execute live-provider requests.
Base URL and authentication#
For the local quickstart, use http://localhost:8080. Use your deployment's HTTPS
address outside that local setup. Every endpoint below uses a Pointsman virtual key:
Authorization: Bearer <your-pointsman-virtual-key>
Set these variables in a private terminal for the curl examples. Replace both placeholders before running; use a model or group your key is permitted to access.
export POINTSMAN_URL='http://localhost:8080'
export POINTSMAN_KEY='<your-pointsman-virtual-key>'
export POINTSMAN_MODEL='<allowed-model-or-group>'
Do not use your provider key or dashboard password as the bearer token. Admin calls
use a separate authentication surface described in the admin API.
The examples use curl and jq; jq constructs JSON safely from shell variables.
Endpoints at a glance#
| Method and path | Result |
|---|---|
POST /v1/chat/completions |
One JSON completion or an SSE stream. |
GET /v1/models |
The caller's available models, usable groups and allowed aliases. |
GET /v1/models/{id} |
One available entry, or 404 if it is unknown or unavailable to the caller. |
POST /v1/feedback |
Accept feedback about an eligible outcome-learning decision. |
POST /v1/quality/assessments |
Record typed quality evidence about a quality-guarded response, citing its X-Quality-Receipt (experimental; how-to). Returns what was stored (201 created, 200 duplicate, 409 conflicting revision); never claims a routing effect. |
Responses, embeddings, audio, batch and rerank APIs are not implemented. Tool pass-through does not execute a tool or authorize the tool's eventual actions.
Create a Chat Completion#
POST /v1/chat/completions accepts Content-Type: application/json.
jq -n --arg model "$POINTSMAN_MODEL" '{
model: $model,
messages: [
{role: "system", content: "Explain technical concepts in plain language."},
{role: "user", content: "What does an AI gateway do?"}
],
max_tokens: 128,
temperature: 0,
stream: false
}' | curl --fail-with-body --silent --show-error \
--dump-header response-headers.txt \
"$POINTSMAN_URL/v1/chat/completions" \
-H "Authorization: Bearer $POINTSMAN_KEY" \
-H 'Content-Type: application/json' \
--data-binary @-
Requests to a live provider may incur charges. A representative response looks like this; IDs, text, model identifiers and token counts vary:
{
"id": "chatcmpl-example",
"object": "chat.completion",
"created": 1800000000,
"model": "support-chat",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "An AI gateway manages your application's calls to AI models."},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 25, "completion_tokens": 18, "total_tokens": 43}
}
| Response field | How to use it |
|---|---|
id, object, created |
Completion identifier, object kind and Unix timestamp in seconds. Use X-Request-ID for gateway investigation. |
model |
The response's request-facing model name; it can be a group. Inspect served-model evidence separately. |
choices[0].message |
Assistant message. For supported tool requests it can contain tool calls instead of ordinary text. |
choices[0].finish_reason |
Why generation ended; distinguish a normal stop, length exhaustion and tool calls where supported. |
usage |
Token accounting when available. Provider usage and estimates have different certainty, especially after interruption. |
service_tier |
Optional provider-reported processing tier when returned. |
guardrail_results |
Optional gateway extension when the configured response reporting includes it. |
On synchronous provider-served responses, X-Served-Provider and X-Provider-Model
help identify what answered. Cache hits and live streams have different header
availability; see the header reference. Do not assume an
absent header has a default value.
Request fields and boundaries#
| Field | Meaning and important boundary |
|---|---|
model |
Concrete model, alias or routing group. Prefer an explicit value in a first integration; omission depends on configured resolution/defaults. |
messages |
Required nonempty conversation. Use lowercase supported roles and the content shape for that role. Text is supported; image input is refused in the v1 exact-tokenizer profile. |
stream |
Omitted/false gives JSON; true gives SSE. |
max_tokens / max_completion_tokens |
Positive output cap. They are aliases; conflicting values are refused. An omitted cap is supplied and bounded by gateway/model/context limits. |
temperature, top_p, stop |
Sampling and stop controls, subject to selected model and adapter support. An omitted temperature is not automatically zero. |
seed, presence_penalty, frequency_penalty |
Adapter-dependent controls. Check the adapter matrix before relying on them. |
logit_bias, logprobs, top_logprobs |
OpenAI-compatible adapter controls. top_logprobs requires logprobs: true; logprob requests bypass cache/coalescing. |
tools, tool_choice, parallel_tool_calls, function strict |
OpenAI-compatible pass-through; Anthropic and Ollama adapters currently refuse these tool requests. |
service_tier |
Processing-tier pass-through where supported, not a routing strategy. |
n |
Omitted or 1. Multiple choices are not supported. |
response_format, reasoning_effort, thinking |
Refused. Do not infer structured-output or reasoning-control support from the API's shape. A model row may fix an effort the operator chose; the client cannot change it. |
user, metadata, store, prompt_cache_key, safety_identifier, stream_options |
Tolerated and dropped. Acceptance does not mean the provider received them or that they were stored. |
The compatibility matrix includes the remaining
explicitly refused controls. The adapter matrix
explains forwarding differences. Unknown fields are not a general pass-through
contract. Context checks use the configured tokenizer mode and model metadata;
chat framing and tool scaffolding still limit provider-exact counting claims. In
exact-tokenizer mode the count is taken after model resolution, with the encoding of
the model or group that will serve, so an unknown model behaves as the key's resolution
policy says and an omitted model is resolved by the blank-model path (key default, tenant
default, semantic group, mode tier, cheapest allowed), the same as in estimate mode, unless the
key or the gateway is set to refuse it (400 model_required).
Request headers#
Use X-Request-ID to supply a correlation ID (1–128 characters from letters,
digits, ., _ and -), or let the gateway generate one. Use
X-Cache-Control: no-cache when deliberately bypassing both cache tiers, for example
while checking provider connectivity. This can increase provider calls and charges.
Other cache, guardrail and routing-related headers are described in the header reference and the feature guides. These headers do not bypass a virtual key's permissions or spending controls.
Stream a completion#
Use the same endpoint with stream: true. curl --no-buffer displays data as it
arrives instead of buffering output:
jq -n --arg model "$POINTSMAN_MODEL" '{
model: $model,
messages: [{role: "user", content: "Explain a gateway in three short sentences."}],
max_tokens: 128,
stream: true
}' | curl --fail-with-body --silent --show-error --no-buffer \
"$POINTSMAN_URL/v1/chat/completions" \
-H "Authorization: Bearer $POINTSMAN_KEY" \
-H 'Content-Type: application/json' \
--data-binary @-
Consume SSE records, not arbitrary TCP chunks. A text event has a
chat.completion.chunk object with choices[].delta; append content deltas to build
the answer. Handle empty deltas, finish information and usage separately. A normal
stream terminates with data: [DONE].
data: {"id":"chatcmpl-example","object":"chat.completion.chunk","created":1800000000,"model":"support-chat","choices":[{"index":0,"delta":{"content":"An AI gateway"},"finish_reason":null}]}
data: [DONE]
This abbreviated illustration omits intervening chunks. Tool calls are emitted as
an assembled chunk when complete, not progressive argument fragments. The gateway
owns upstream usage requests; sending stream_options does not change that. For a provider
configured as a registry row, upstream stream usage is requested only when the operator set the row's
streamUsage quirk; otherwise the stream carries no usage chunk.
Check both the initial HTTP status and error payloads arriving after the stream starts. HTTP 200 cannot become a different status after headers have been sent. An interrupted stream may contain partial output and estimated usage. Avoid blindly retrying it as if no provider work occurred.
Discover available models#
curl --fail-with-body --silent --show-error \
"$POINTSMAN_URL/v1/models" \
-H "Authorization: Bearer $POINTSMAN_KEY" | jq .
The response is a list object with data entries. A concrete model uses
object: "model"; a routing group uses object: "model-group". Entries have id,
object, created and owned_by. Optional metadata includes family, tier,
cost_per_1k, modality, context, params, tags, aliases, deprecated and
alias_for. Omitted metadata means it was not supplied, not that a capability or
limit is unlimited. cost_per_1k is configured input pricing metadata; it is not a
complete input/output price quote or live provider invoice.
Retrieve a single entry by URL-encoding its identifier:
MODEL_PATH=$(jq -rn --arg id "$POINTSMAN_MODEL" '$id | @uri')
curl --fail-with-body --silent --show-error \
"$POINTSMAN_URL/v1/models/$MODEL_PATH" \
-H "Authorization: Bearer $POINTSMAN_KEY"
Discovery is scoped to the caller. A 404 on this endpoint does not distinguish an unknown identifier from one the key cannot access. Listing a model is not proof that the provider is healthy or that every optional request control is supported.
Send outcome feedback#
POST /v1/feedback is for the outcome-learning router. A weighted-random or direct
model request does not become trainable just because you send a rating.
For an eligible decision, save X-Decision-Receipt from the completion response
and send it as decision_id. Prefer this signed receipt to the bare X-Decision-Id
when using multiple gateway instances. Use the same virtual key that made the call.
export POINTSMAN_DECISION='<X-Decision-Receipt-from-the-response>'
jq -n --arg decision "$POINTSMAN_DECISION" '{
decision_id: $decision,
rating: 1,
revision: 0
}' | curl --fail-with-body --silent --show-error \
"$POINTSMAN_URL/v1/feedback" \
-H "Authorization: Bearer $POINTSMAN_KEY" \
-H 'Content-Type: application/json' \
--data-binary @-
| Field | Contract |
|---|---|
decision_id |
Required nonblank signed receipt or eligible decision ID. Ownership and age are checked. |
rating |
Integer: 1 for positive or −1 for negative. Zero is refused. Required unless retract is true, and refused with it. |
revision |
Optional integer, defaults to 0; range 0 through 9,007,199,254,740,991. Reuse a revision on a retry; increase it for an edited rating or a retraction. |
retract |
Optional boolean. true withdraws the decision's rating (send it with a higher revision and no rating); the decision returns to its unrated reward. A retraction without a revision of at least 1 is refused with 400. Withdrawing the only quality of a rate-composition decision is recorded and changes nothing, because such a decision has no unrated reward to return to. Not available for decisions made before the learning semantics changed (17 October 2026). |
A rating revises the decision it names; it does not count as an extra observation.
A valid submission normally returns 202 {"accepted":true}. This acknowledges
submission, not proof that a policy changed. Unknown, expired or ineligible
provenance can be ignored without revealing whether someone else's decision exists.
A disabled feedback service can return 503; feedback rate limits can return 429 with
Retry-After. Use your actual task result as feedback, such as whether an extraction
passed validation. How learning uses feedback.
Errors and retries#
Most gateway errors use an error object with message and type; code and
param are included where provided. Parse defensively rather than requiring every
field. For example, an unsupported control can identify both the field and the
unsupported_request_control code.
| Status or situation | What to investigate |
|---|---|
| 400 | Invalid shape, unsupported control, invalid token cap or an incompatible request. Correct it before retrying. |
| 401 / 403 | Key validity, environment, authorization or scope. Dashboard credentials are not application credentials. |
| 402 | Spending restrictions. Inspect the error and effective limits; retries alone do not create budget. |
| 404 on model lookup | Unknown or unavailable model. Recheck discovery with the same key. |
| 429 | Rate/capacity refusal. Honor Retry-After when present and reduce concurrency or request rate. |
503 budget_recovering |
The budget this request is charged to is held until its balance is established: the counter store is starting or activating a new budget generation (transient: retry with backoff, usually clears in seconds), or the operator must attest it after a counter-store loss or a declared database restore (retries will NOT clear it; only the operator's recovery does). The refusal happens before any provider call. Bound your retries; do not retry indefinitely. |
| 5xx | Inspect the error code, request ID and dependency state. Budget recovery and upstream outages require different responses. |
| Error after SSE begins | Preserve partial output and error details; initial HTTP 200 is not a successful completion. |
These categories are not an exhaustive error-code catalogue. Use bounded retries with backoff for transient failures, and consider whether the upstream may already have processed the request. This page does not promise exactly-once completion or idempotent billing for a retried chat request.
When reporting an issue, include a redacted request shape, gateway version, request ID, status/error code and whether it streamed or hit cache. Exclude credentials and sensitive prompt content. Request investigation.
Implementation references#
The contract above was checked against the current chat request, chat response, model entry, feedback request and the controllers. Runtime/provider verification remains part of release qualification.