Copy every request, as a trace, to your own monitoring tool — add, change and remove destinations.
Every request can be copied, as a trace, to your own monitoring tool: Langfuse, LangSmith, Datadog, an S3 bucket, a webhook and the rest of the destinations. You add a destination once; each request is sent there after it has been settled.
Every destination route is free and takes a management key. The openai SDK has no observability resource, so call the routes with httpx.
import os
import httpx
headers = {"Authorization": f"Bearer {os.environ['OPENDUNES_MANAGEMENT_KEY']}"}
resp = httpx.post(
"https://opendunes.com/v1/observability/destinations",
headers=headers,
json={
"name": "Souk Bot traces",
"type": "langfuse",
"config": {
"publicKey": os.environ["LANGFUSE_PUBLIC_KEY"],
"secretKey": os.environ["LANGFUSE_SECRET_KEY"],
},
"sampling_rate": 1,
"privacy_mode": False, # True leaves the input and output out of every trace
},
)
destination = resp.json()["data"] # 201 — secrets come back maskedA missing setting is a 400 naming it, such as config.secretKey is required for langfuse.
The user field and a session_id travel on the trace, and a destination's filter rules can select on them:
from openai import OpenAI
client = OpenAI(base_url="https://opendunes.com/v1", api_key=os.environ["OPENDUNES_API_KEY"])
client.chat.completions.create(
model="anthropic/claude-sonnet-5",
messages=[{"role": "user", "content": "Wach kayen iPhone 16?"}],
user="customer-4521",
extra_body={"session_id": "chat-2026-09-24-001"},
)httpx.get("https://opendunes.com/v1/observability/destinations", headers=headers)
# → { "data": [ … ], "total_count": n }
httpx.patch(
f"https://opendunes.com/v1/observability/destinations/{destination['id']}",
headers=headers,
json={"enabled": False},
)
httpx.delete(f"https://opendunes.com/v1/observability/destinations/{destination['id']}", headers=headers)
# → { "deleted": true }