Guides

Use the OpenAI SDK

Call the Azta API from the official OpenAI Python and Node SDKs, and keep the SDK's automatic retries safe with a per-call Idempotency-Key.

The Azta API speaks OpenAI's Responses format, so the official OpenAI SDKs work with a different base URL and key. Two things differ from a plain OpenAI call: depth is an Azta field the SDK does not know, and the SDK's automatic retries need an Idempotency-Key that you set yourself.

Install

Terminal
pip install openai==3.37.0

Python 3.12 and Node 24 are the tested versions.

Point the client at Azta

The base URL is https://api.azta.ai/v1 and the key is your Azta API key. Read both from the environment, never from source code.

The full examples below build the client this way: OpenAI(base_url=…, api_key=…) in Python and new OpenAI({ baseURL, apiKey }) in Node.

Create, retrieve and cancel

Create with background: true, pass depth through the SDK's escape hatch for extra fields (extra_body in Python, a widened body type in Node), and poll with responses.retrieve. POST /v1/responses/{id}/cancel stops a run; call it with client.responses.cancel.

Python
"""Ask Azta one question through the OpenAI Python SDK and print the sources."""

import os
import sys
import time
import uuid

from openai import OpenAI

api_key = os.environ.get("AZTA_API_KEY")
if not api_key:
    sys.exit("Set AZTA_API_KEY to your Azta API key")

client = OpenAI(
    base_url=os.environ.get("AZTA_BASE_URL", "https://api.azta.ai/v1"),
    api_key=api_key,
)
QUESTION = "Mikor alkalmazandó a fordított adózás építőipari szolgáltatásnál?"

# One key per question. The SDK retries a failed create on its own and sends
# no idempotency header of its own, but it re-sends this per-call header, so
# every retry is the same request and is charged once.
idempotency_key = str(uuid.uuid4())

response = client.responses.create(
    model="azta-agent",
    input=QUESTION,
    background=True,
    extra_body={"depth": "standard"},
    extra_headers={"Idempotency-Key": idempotency_key},
)

while response.status in ("queued", "in_progress"):
    time.sleep(5)
    response = client.responses.retrieve(response.id)

if response.status != "completed":
    code = response.error.code if response.error else response.status
    sys.exit(f"Error: {code}")

print(response.output_text)
print()
print("Sources:")
for source in (response.model_extra or {}).get("sources", []):
    print(f"[{source['number']}] {source['title']} {source['url']}")

Streaming

Pass stream=True (stream: true in Node) and iterate the events. response.output_text.delta events carry the text as it is written; response.output_text.done carries 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. See Responses for the stream's deadline and what dropping the connection does.

Retries and the Idempotency-Key

The OpenAI SDKs retry a failed request on their own: a connection error, a 408, 409, 429 or any 5xx, up to two more times. They send no idempotency header on those retries, so on their own a retried create could run, and be charged, twice.

Set the key per call, once per question, as extra_headers={"Idempotency-Key": key} in Python and { headers: { 'Idempotency-Key': key } } in Node, exactly as the examples above do. The SDK re-sends a per-call header on every automatic retry, so all attempts carry the same key and Azta treats them as one request.

This site's CI proves it: a test makes the first create fail with a 500, lets the SDK retry, and checks that both requests carry the same Idempotency-Key. Create a new key for each new question, and reuse it only when you retry that same question yourself. See Responses for how the key is scoped.

Read the sources

sources[] is an Azta field, so the SDK keeps it as an extra: response.model_extra["sources"] in Python, and a cast in Node. Each annotation's source_number points at the source with the same number. Sources describes the record and how to render citations from the annotation offsets.

Verify webhooks

The OpenAI SDKs verify Standard Webhooks signatures, which is the scheme Azta uses. Pass the raw request body, the headers and the endpoint secret (whsec_…). Both samples refuse to run without AZTA_WEBHOOK_SECRET:

Python
"""Verify and parse an Azta webhook with the OpenAI Python SDK."""

import os

from openai import OpenAI


def unwrap_event(payload: str, headers: dict[str, str]):
    """Return the event, or raise if the signature or timestamp is wrong.

    Pass the raw request body, exactly as received.
    """
    secret = os.environ.get("AZTA_WEBHOOK_SECRET")
    if not secret:
        raise RuntimeError("Set AZTA_WEBHOOK_SECRET to your endpoint's whsec_ secret")
    client = OpenAI(api_key=os.environ.get("AZTA_API_KEY", "unused"))
    return client.webhooks.unwrap(payload, headers, secret=secret)

unwrap throws if the signature or timestamp is wrong. The event is thin, so fetch the answer with responses.retrieve(event.data.id). Webhooks has the payload, the retry schedule, and a verifier that does not need the SDK (examples/webhooks/).

What is not supported

  • previous_response_id and conversation are refused with 400 unsupported_parameter, because the API keeps no conversation. Send the whole conversation as input, as described in Responses.
  • tools are not supported. Azta looks up the provisions it cites itself.

On this page