Documentation

Start calling the API in a few minutes

TunAI exposes an OpenAI-compatible API. Point any OpenAI SDK at https://api.tunai.tn/v1 with your API key.

Guide: use TunAI with the Oh-My-Pi coding agent

Install, connect your key, pick models and set defaults in about five minutes.

Quick start

Three steps to your first request

1. Create an API key

Go to the API keys page and create a key. Copy it — it's shown only once.

2. Add credits

Top up your balance on the billing page. Each request is metered by token usage and deducted from your balance.

3. Make your first request

Install the OpenAI SDK (pip install openai / npm install openai) and call the API:

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",          # your sk-tunai-... key
    base_url="https://api.tunai.tn/v1",
)

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)

print(response.choices[0].message.content)

Streaming

# Streaming (Server-Sent Events)
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Write a haiku."}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content or ""
    print(delta, end="", flush=True)

The stream ends with a data: [DONE] sentinel, exactly as OpenAI's does.

Tool calling, JSON mode and embeddings

Parameters are forwarded to the provider, so the OpenAI SDK's full surface works — tools, tool_choice, response_format, seed, and the penalty parameters.

Tool calling and JSON mode

# Tool calling / function calling
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What's the weather in Tunis?"}],
    tools=[{
        "type": "function",
        "function": {
            "name": "get_weather",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        },
    }],
)
print(response.choices[0].message.tool_calls)

# JSON mode
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "List 3 Tunisian cities as JSON."}],
    response_format={"type": "json_object"},
)

Embeddings

response = client.embeddings.create(
    model="text-embedding-3-small",
    input=["Tunis", "Sfax", "Sousse"],
)
print(len(response.data), "vectors x", len(response.data[0].embedding), "dims")

Token usage

# Every response reports real token usage
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.usage.prompt_tokens, response.usage.completion_tokens)

# For streaming, ask for a final usage chunk explicitly
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.usage:
        print("total tokens:", chunk.usage.total_tokens)

Rate limits and request ids

Each key is limited to a per-minute request cap by default. You can set a lower limit, a monthly budget, an expiry, or restrict a key to specific endpoints on the API keys page.

Every response carries the current limit state:

x-ratelimit-limit-requests:     120
x-ratelimit-remaining-requests: 119
x-ratelimit-reset-requests:     60s
x-request-id:                   req_9e0d436bb573482f85d432f779d12304

Quote the x-request-id in any support request — it maps to the exact call, including what it cost.

Use it with your tools

Any OpenAI-compatible client works by setting the base URL + your key.

Cursor → Settings → Models → enable “Override OpenAI Base URL”, paste the base URL and your key, then add a model id from /v1/models.

Base URL:  https://api.tunai.tn/v1
API Key:   YOUR_API_KEY        # your sk-tunai-... key
Model:     gpt-4o-mini    # any id from GET https://api.tunai.tn/v1/models

API reference

Authenticate with Authorization: Bearer YOUR_API_KEY

Chat completions

POST https://api.tunai.tn/v1/chat/completions

Create a chat completion with any supported model. Supports stream, stream_options, temperature, max_tokens, top_p, stop, tools, tool_choice, response_format, seed, presence_penalty and frequency_penalty.

Embeddings

POST https://api.tunai.tn/v1/embeddings

Accepts a string or an array of strings, plus optional dimensions.

List and retrieve models

GET https://api.tunai.tn/v1/models
GET https://api.tunai.tn/v1/models/{model}

Public — no API key needed. Only models we can actually serve are listed.

Available models

Models accessible through the API

Could not load the live model list. See GET https://api.tunai.tn/v1/models.

Error codes

Errors are returned in OpenAI's { error: { message, type, code } } shape

400invalid_request_errorInvalid parameter — `param` names the offending field.
401invalid_request_errorMissing, invalid, revoked, or expired API key.
402insufficient_quotaOut of balance, or the key hit its monthly budget.
403invalid_request_errorThis key isn't permitted to use that endpoint.
404invalid_request_errorUnknown model id or route.
429rate_limit_errorRate limit exceeded for this key.
502 / 503api_errorUpstream provider error or temporarily unavailable.

Best practices

  • •Keep your key secret: never commit it or expose it in client-side code.
  • •Handle 429s: back off and retry on rate limits.
  • •Watch your balance: a 402 means you're out of credits — top up to resume.
  • •Pick the right model: cheaper models for simple tasks keeps costs down.