SDKs and clients

ODEN is a plain JSON-over-HTTPS API, so no SDK is required. Copy-paste a minimal Python or TypeScript client, or call it directly from any language.

Documentation1 min readUpdated 2026-07-30

ODEN is a plain HTTPS endpoint that sends and receives JSON. No SDK is required — it works from any language with an standard HTTP client. If you prefer a structured, typed wrapper with built-in retries, copy one of these production-ready clients.

Synchronous Python client#

A single-file client with retry and typing. Drop it in as oden.py:

import os, time
from dataclasses import dataclass
import requests

@dataclass
class Citation:
    title: str
    url: str
    score: float
    snippet: str | None = None

class Oden:
    def __init__(self, key: str | None = None, base: str = "https://api.oden-api.com"):
        self.key = key or os.environ["ODEN_KEY"]
        self.base = base

    def search(self, query: str, *, answer: bool = True, depth: str = "advanced",
               include_snippets: bool = False, retries: int = 3) -> dict:
        body = {"query": query, "answer": answer, "depth": depth,
                "include_snippets": include_snippets}
        for attempt in range(retries + 1):
            r = requests.post(
                f"{self.base}/search",
                headers={"Authorization": f"Bearer {self.key}"},
                json=body, timeout=30,
            )
            if r.status_code == 429 and attempt < retries:
                time.sleep(2 ** attempt)
                continue
            r.raise_for_status()
            return r.json()

# Usage
oden = Oden()
data = oden.search("what is retrieval-augmented generation", include_snippets=True)
print(data["results"]["answer"])

Asynchronous Python client (httpx)#

For high-throughput async services built on FastAPI, Litestar, or AsyncIO agent loops:

import os, asyncio
import httpx

class AsyncOden:
    def __init__(self, key: str | None = None, base: str = "https://api.oden-api.com"):
        self.key = key or os.environ["ODEN_KEY"]
        self.base = base

    async def search(self, query: str, *, answer: bool = True, depth: str = "advanced",
                     include_snippets: bool = False, timeout: float = 25.0, retries: int = 3) -> dict:
        payload = {"query": query, "answer": answer, "depth": depth, "include_snippets": include_snippets}
        headers = {"Authorization": f"Bearer {self.key}"}

        async with httpx.AsyncClient(timeout=timeout) as client:
            for attempt in range(retries + 1):
                res = await client.post(f"{self.base}/search", headers=headers, json=payload)
                if res.status_code == 429 and attempt < retries:
                    await asyncio.sleep((2 ** attempt) + 0.5)
                    continue
                res.raise_for_status()
                return res.json()
        raise RuntimeError("Async search failed: retries exhausted")

TypeScript client with timeout & abort signal#

A zero-dependency TypeScript client designed for Node 18+, Bun, Deno, and Next.js:

export interface OdenCitation {
  title: string;
  url: string;
  score: number;
  snippet?: string;
}

export interface OdenResponse {
  query: string;
  trace_id: string;
  cached: boolean;
  results: {
    answer?: string;
    citations: OdenCitation[];
  };
}

export class Oden {
  private key: string;
  private base: string;

  constructor(key?: string, base = "https://api.oden-api.com") {
    this.key = key || process.env.ODEN_KEY || "";
    this.base = base;
    if (!this.key) throw new Error("Missing ODEN_KEY");
  }

  async search(
    query: string,
    opts: { answer?: boolean; depth?: "advanced" | "basic"; includeSnippets?: boolean; timeoutMs?: number } = {}
  ): Promise<OdenResponse> {
    const { answer = true, depth = "advanced", includeSnippets = false, timeoutMs = 25000 } = opts;
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), timeoutMs);

    try {
      const resp = await fetch(`${this.base}/search`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${this.key}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          query,
          answer,
          depth,
          include_snippets: includeSnippets,
        }),
        signal: controller.signal,
      });

      if (!resp.ok) {
        const err = await resp.json().catch(() => ({}));
        throw new Error(`ODEN error ${resp.status}: ${err.message || resp.statusText}`);
      }

      return resp.json() as Promise<OdenResponse>;
    } finally {
      clearTimeout(timer);
    }
  }
}

Terminal CLI bash helper#

Add this shell function to your ~/.bashrc or ~/.zshrc for instant command-line search lookups:

oden() {
  curl -s -X POST "https://api.oden-api.com/search" \
    -H "Authorization: Bearer $ODEN_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"query\": \"$*\", \"answer\": true}" | jq -r '.results.answer'
}
# Usage: oden What is the EU Artificial Intelligence Act?

Any other language#

If your language or environment can issue an HTTPS POST request with a JSON payload and an Authorization header, it integrates with ODEN seamlessly. See the Search endpoint for the HTTP specification and OpenAPI specification for code generation tools.

Next steps#

  • Quickstart — the same calls, inline.
  • Use cases — ODEN inside RAG, LangChain, LlamaIndex and tool-use loops.