Responses
Create a response, stream it or poll it, cancel it, ask follow-up questions and retry safely.
POST /v1/responses asks Azta one question. The answer cites the provisions it rests on, so every answer links to the provisions it cites. This guide covers how to wait for an answer, how to ask a follow-up and how to retry without paying twice.
Stream or background
Set exactly one of stream and background to true.
stream: trueanswers200as server-sent events, in OpenAI's Responses event vocabulary.response.output_text.deltaevents carry the text as it is written.response.output_text.donecarries the whole text and is the authoritative one, so replace what you built from deltas with it. Annotations and sources arrive only in the closing frames.background: trueanswers202with the response inqueued. PollGET /v1/responses/{id}untilstatusiscompleted,failedorcancelled. The quickstart does this every 5 seconds.
There is no partial text while a response runs. GET /v1/responses/{id} returns an empty output while the status is queued or in_progress; sources is [] until it is completed.
The stream has a deadline of 900 seconds. A stream that reaches it ends with response.failed, but that ends the stream, not the run. The run keeps executing, and it is charged if it completes. Poll GET /v1/responses/{id} for its real outcome, or cancel it. Dropping the connection does not cancel the run either, and reconnecting does not replay the stream.
Cancel a response
POST /v1/responses/{id}/cancel stops a run. A cancel after answer text has started streaming is charged; a cancel before any answer text was delivered is free (see Pricing). Cancelling a response that has already ended answers 409 response_finished. A cancel creates and charges nothing by itself, and a repeat answers the run's current state.
Depth
depth is standard by default. Send deep only when you want the run to research further before it answers; it is priced higher. The response echoes depth. Any other value is 400 invalid_request with param: "depth". See Pricing for the amounts.
Jurisdiction
X-Jurisdiction names the countries whose law the answer draws on, as a comma-separated list of ISO country codes, in any case and spacing. Without it the default is hu. us, oecd, ifrs and unknown codes are refused with 400 unsupported_jurisdiction.
Follow-up questions
The API is stateless: it keeps no conversation for you. To ask a follow-up, send the whole conversation as input, an item array whose last item is the new question with role: "user".
#!/usr/bin/env bash
# Ask a follow-up question. The API is stateless, so send the whole
# conversation as `input`; the last item is the new user question.
# Needs curl, jq and uuidgen.
set -euo pipefail
: "${AZTA_API_KEY:?Set AZTA_API_KEY to your Azta API key}"
BASE_URL="${AZTA_BASE_URL:-https://api.azta.ai/v1}"
headers="$(mktemp)"
body="$(mktemp)"
trap 'rm -f "$headers" "$body"' EXIT
# One key per question, reused on every retry of it.
IDEMPOTENCY_KEY="$(uuidgen | tr 'A-Z' 'a-z')"
payload='{
"model": "azta-agent",
"background": true,
"input": [
{"role": "user", "content": "Mennyi az áfa mértéke?"},
{"role": "assistant", "content": "Az általános kulcs 27%."},
{"role": "user", "content": "És építőipari szolgáltatásnál?"}
]
}'
# retry_after DEFAULT prints the Retry-After seconds, else DEFAULT.
retry_after() {
local value
value="$(grep -i '^retry-after:' "$headers" | tail -n 1 | cut -d: -f2 | tr -d ' \r')"
if [[ "$value" =~ ^[0-9]+$ ]]; then
echo "$value"
return
fi
echo "${1}"
}
for attempt in 1 2 3; do
status="$(curl -sS -D "$headers" -o "$body" -w '%{http_code}' "$BASE_URL/responses" \
-H "Authorization: Bearer $AZTA_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d "$payload")"
case "$status" in
200 | 202) break ;;
429 | 500 | 503) [ "$attempt" -lt 3 ] && sleep "$(retry_after 1)" ;;
*) echo "Error: http_$status" >&2; exit 1 ;;
esac
done
[ "$status" = 200 ] || [ "$status" = 202 ] || exit 1
id="$(jq -r '.id' "$body")"
while true; do
status="$(curl -sS -D "$headers" -o "$body" -w '%{http_code}' "$BASE_URL/responses/$id" \
-H "Authorization: Bearer $AZTA_API_KEY")"
case "$status" in
429 | 503) sleep "$(retry_after 5)"; continue ;;
200) ;;
*) echo "Error: http_$status" >&2; exit 1 ;;
esac
state="$(jq -r '.status' "$body")"
case "$state" in
completed) break ;;
failed | cancelled) echo "Error: $(jq -r '.error.code // .status' "$body")" >&2; exit 1 ;;
esac
sleep 5
done
jq -r '[.output[].content[] | select(.type == "output_text") | .text] | join("")' "$body"A previous response's output can go back as an item, unchanged, so you do not need to rebuild it. Only the most recent turns are used: at most 40 messages and 200,000 characters, oldest dropped first, each turn kept whole or not at all. A system or developer item is accepted and not replayed into the model, so put instructions in the user turn.
previous_response_id and conversation are refused with 400 unsupported_parameter, because there is no server-side conversation to point at.
Idempotency-Key
Send an Idempotency-Key header on every POST under /v1: 1 to 255 printable ASCII characters, scoped to your API key and kept for 24 hours. A retry that reuses the key is the same request and is charged once. A retry without Idempotency-Key is a new request and is charged again. The OpenAI SDKs add no such header on their own retries, so set it yourself.
| Repeat | Answer |
|---|---|
| Same key, same request, the response exists | The stored response as JSON, with Idempotent-Replayed: true |
| Same key, still being processed | 409 idempotency_key_in_use |
| Same key, a different request | 400 idempotency_key_reused |
A request that is refused frees its key, so you can fix it and send it again. See Errors for which failures to retry.
Search provisions POST
Search the current provisions of the law in force, with no model call. The words of `query` are all required, and one word is enough. A word starting with `-` is dropped and phrases are not searched. A hit without a `unit_id` is left out. `X-Jurisdiction` names at most 3 countries; when none of them can be searched by provision the call is `unsupported_jurisdiction`, and free. Charged per call. A sandbox key gets sample records.
Sources
The source record every answer carries, how its url is chosen, and how to render citations from annotation offsets.