A private text-generation API. Send a chat-style request, get a reply — streaming or all at once. Access is by API key issued from the admin panel.
https://api.shieldie.aiPOST /v1/messagesx-api-key: sk-shd-… (or Authorization: Bearer sk-shd-…)Keys are issued from the password-protected admin panel. A key is
shown once, at creation — copy it then. Present it on every request in the
x-api-key header.
A JSON body with a list of messages. The model field is optional — there is a
single model, default, and it is used whether or not you name one.
| field | |
|---|---|
messages | required — array of {"role":"user"|"assistant","content":"…"} |
max_tokens | required — positive integer; caps the answer (approximately, see Errors and limits) |
system | optional — a system instruction string |
stream | optional — true for server-sent events |
model | optional — accepted and ignored; always default |
curl https://api.shieldie.ai/v1/messages \
-H "x-api-key: $SHIELDIE_API_KEY" \
-H "content-type: application/json" \
-d '{
"max_tokens": 256,
"messages": [{"role": "user", "content": "Napisz jedno zdanie po polsku."}]
}'
{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "default",
"content": [{ "type": "text", "text": "…" }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 12, "output_tokens": 34 }
}
import requests
r = requests.post(
"https://api.shieldie.ai/v1/messages",
headers={"x-api-key": "sk-shd-...", "content-type": "application/json"},
json={
"max_tokens": 256,
"messages": [{"role": "user", "content": "Hello!"}],
},
)
print(r.json()["content"][0]["text"])
Set "stream": true. The response is a text/event-stream with these events:
message_start → content_block_start →
content_block_delta (repeated, each carrying a text_delta) →
content_block_stop → message_delta → message_stop,
with ping keep-alives: the stream opens within a few seconds of the model starting
and carries a ping at least every 15 seconds while the model works, even before the first
text. A failure after the stream opened arrives as an error event.
curl -N https://api.shieldie.ai/v1/messages \
-H "x-api-key: $SHIELDIE_API_KEY" \
-H "content-type: application/json" \
-d '{"max_tokens":128,"stream":true,
"messages":[{"role":"user","content":"Count to five."}]}'
Pass tools with your request. The model may answer with a tool_use
block instead of text; your client runs the tool and sends the outcome back as a
tool_result in the next request. The server never executes anything.
curl https://api.shieldie.ai/v1/messages \
-H "x-api-key: $SHIELDIE_API_KEY" -H "content-type: application/json" \
-d '{
"max_tokens": 512,
"tools": [{
"name": "get_weather",
"description": "Get the current weather for a city",
"input_schema": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}],
"messages": [{ "role": "user", "content": "What is the weather in Kraków?" }]
}'
A tool call comes back as:
{
"stop_reason": "tool_use",
"content": [
{ "type": "tool_use", "id": "toolu_…", "name": "get_weather", "input": { "city": "Kraków" } }
]
}
Run the tool, then continue the conversation with the result:
"messages": [
{ "role": "user", "content": "What is the weather in Kraków?" },
{ "role": "assistant", "content": [
{ "type": "tool_use", "id": "toolu_…", "name": "get_weather", "input": { "city": "Kraków" } } ] },
{ "role": "user", "content": [
{ "type": "tool_result", "tool_use_id": "toolu_…", "content": "18°C, sunny" } ] }
]
Use tool_choice to steer it: {"type":"auto"} (default),
{"type":"any"} (must call some tool),
{"type":"tool","name":"…"} (must call that one; the name must be a declared tool), or
{"type":"none"} (no tool call this turn). Any other value is a 400.
Tool support is best-effort: one tool call per turn (no parallel calls), streaming
responses that carry a tool call are delivered buffered rather than incrementally, and
input_schema is guidance — validate the arguments on your side.
A call is recognised only when the model ends its reply with it, on a line
of its own, naming one of the tools you declared. A call merely quoted in the reply (say,
one that appeared in a tool result), a second call, or an undeclared name comes back as
plain text with stop_reason: "end_turn". At most 64 tools per request.
| method / path | what |
|---|---|
GET /v1/models | List the available model (needs a key). |
POST /v1/messages/count_tokens | Approximate input token count (about three characters per token, tool definitions included). |
GET /health | Liveness check (public). |
An error body looks like {"type":"error","error":{"type":"…","message":"…"}}.
| status / type | when |
|---|---|
400 invalid_request_error | A malformed request, unsupported content (images, documents), invalid Unicode (lone surrogates), or a NUL character in the system prompt or tool definitions. |
401 authentication_error | Missing, wrong, revoked or expired key. |
413 request_too_large | The system prompt plus tool definitions are too large (about 100 kB), the prompt is over your key's size cap, or it is too long for the model. |
429 rate_limit_error | The server is busy, or your key's daily limit
(or budget) is reached. Always carries Retry-After in seconds: short when busy,
until 00:00 UTC for a daily limit. Wait at least that long before retrying. |
529 overloaded_error | The model is temporarily overloaded. Carries
Retry-After; retry after that. It does not count toward your daily limit. |
502 / 504 | The model failed or did not answer in time;
a later retry may succeed. A 502 with Retry-After means the model
is unavailable for a while; it does not count toward your daily limit. |
When the server is busy a request waits briefly (up to about 20 s) for a free slot before a
429 is returned.
tool_result too.max_tokens caps the answer (counted generously, at five characters per
token; the model's thinking is not part of it). stop_sequences and
temperature are accepted but not enforced. A reply cut at max_tokens or
at the server's own output ceiling ends with
stop_reason: "max_tokens" (so does one that ran out of context window); one
the model declined, with
"refusal" (never a tool call) — check stop_reason before using
the content.count_tokens is an estimate; usage is reported per request in the
Messages API's shape: input_tokens is the uncached input, and
cache_creation_input_tokens / cache_read_input_tokens count the
cached part (most of a prompt is usually there). When streaming, the full counts arrive in
the final message_delta.