Your Langfuse Traces Are Already Yours. Here Is How You Get Them Out.
Langfuse is open only if you can query and export traces without living in the UI; the Public API and a boring nightly job are how Harbor Desk actually owns its data.

Basic Auth on /api/public, the typed api namespace on the v4 and v5 SDKs, and a 15-to-30-second ingest lag: how to query, export, and automate Langfuse without clicking through the UI.
The UI can show you one failing ticket. It cannot fill tomorrow's review queue.
In this article: You will learn which of the three Langfuse APIs Harbor Desk actually uses, how Basic Auth works on the Langfuse Public API, and how the Python v4 and JS/TS v5 SDKs expose that surface as
langfuse.api. We cover the high-performance defaults (observations,scores_v3,metrics), the ingest lag that makes same-process query-after-flush fail, the other exits (UI export, blob storage, CLI, MCP), and a small nightly job that turns yesterday's low-score tickets into a review queue.
You have been sending traces for days. Harbor Desk classifies a support ticket, retrieves a policy snippet, and drafts a reply, and every turn lands in Langfuse. Then someone asks for last night's failures: every ticket where the policy check came back false, as a list the team can review before standup. The UI will show you those traces one at a time. That is not a review queue.
Langfuse is open, and the traces you have been sending are yours. The Langfuse Public API is how you read them back without clicking through the product. You get Basic Auth on /api/public, typed wrappers on the official SDKs, export when a human or a warehouse needs a dump, and a small nightly job that stays boring on purpose.
This article is that map.
Three APIs: do not mix them up
Langfuse exposes three different APIs. Mixing them up is the first way a Harbor Desk job goes looking in the wrong place.
- Project-level Public API (
/api/public): CRUD for traces, evals, prompts, and project config. This is the one Harbor Desk uses. - Organization-level APIs: provision projects, manage users via SCIM, and set permissions.
- Instance Management API: administer organizations on a self-hosted install.
If you are pulling ticket traces, scores, or prompt versions, you want /api/public. The other two are for provisioning and for operating a self-hosted fleet.

Cloud hosts for the public surface:
- EU:
https://cloud.langfuse.com/api/public - US:
https://us.cloud.langfuse.com/api/public - Japan:
https://jp.cloud.langfuse.com/api/public - HIPAA:
https://hipaa.cloud.langfuse.com/api/public
Authenticate with Basic Auth. Username is the public key. Password is the secret key.
curl -u public-key:secret-key https://cloud.langfuse.com/api/public/projects
The OpenAPI spec is the machine-readable contract. The human reference is the page you actually read.
Prefer the SDK api namespace
You can curl the REST surface. For anything you will run more than once, prefer the official SDK wrapper. Both official SDKs expose the same REST surface as langfuse.api.
From Python SDK v4 and JS/TS SDK v5, the high-performance defaults are:
api.observations: the oldobservations_v2alias is goneapi.scores_v3/api.scoresV3:api.scoresv2 reads are deprecatedapi.metrics: the old v2 alias is gone
api.legacy.* still hits the deprecated endpoints. Langfuse Cloud serves those until 16 November 2026. Do not start a new Harbor Desk job on them.

The Python shape looks like this. The JS/TS v5 client exposes the same methods on langfuse.api; the scores helper is camelCase (scoresV3) on that SDK.
from langfuse import get_client
langfuse = get_client()
observations = langfuse.api.observations.get_many(
trace_id="abcdef1234",
type="GENERATION",
limit=100,
fields="core,basic,usage",
)
Use parent_observation_id on the response if you need to rebuild the tree. You asked for generations on one ticket. You get back the model calls, and the parent ids are how you put them back under the span that orchestrated them.
The same api object that feeds a dashboard also answers metrics queries:
metrics = langfuse.api.metrics.get(query=query)
Gotcha: calling the removed v2 aliases on SDK v4/v5, or expecting a just-flushed trace to be queryable in the same millisecond.
New data is not queryable in the same breath
Ingest is asynchronous. New data is typically queryable in 15 to 30 seconds after it lands. A script that flushes a trace and immediately queries it in the same process will often miss the trace.
That is not a bug in get_many. Ingest and query are not the same path. If you are proving a pipeline, wait. If you are writing the nightly job, you are already looking at yesterday, so the lag does not matter.

Harbor Desk's nightly job
A Harbor Desk nightly job is boring on purpose. It lists yesterday's scores where mentions-policy is false, and it opens a review queue. If you added a helpfulness judge, filter that too.
That is api.scores_v3 plus api.observations. It is not a new product. The scores tell you which tickets failed the check. The observations give you the generations a reviewer needs to see why.

Keep the keys in the environment. Keep the script on a cron. Resist the urge to replace it with a chat agent that "looks around" in Langfuse. The job has one job.
The other exits
The Public API is the path you automate. It is not the only door.
Export from the UI when a human wants a CSV or JSON of what they are looking at. That is the right tool for a one-off dump, not for a review queue that has to exist every morning.
Export to blob storage on S3, GCS, or Azure for enriched observations, scores, and the older legacy exports. Use this when Harbor Desk traces should land in the warehouse every night. The nightly job answers "which tickets failed." The blob export answers "put the rest of the fleet where analytics already lives."
CLI talks to the full API from the command line. It is aimed at agents and power users. If you already installed the Langfuse agent skill, this is one of the tools it reaches for.
MCP server and the agent skill are how a coding agent searches docs, issues, and your project data. They are useful. They are not a substitute for the nightly job, which should be a boring script with keys in the environment.

Do this today
You do not need a warehouse to prove the API is yours.
- Authenticate once. Run the
curl -u public-key:secret-keycall against/api/public/projectson the Cloud host you actually use. If that fails, fix the keys before you write any Python. - Query a real ticket. Call
api.observations.get_manywith atrace_idyou already have from a Harbor Desk turn,type="GENERATION", andfields="core,basic,usage". Confirm you see the classify and draft generations. - Prove the lag to yourself. Flush a new trace and query it in the same process. Then wait 20 seconds and query again. The empty first response is the lesson.
- Sketch the nightly filter. Write down the score names you will select on (
mentions-policy, andhelpfulnessif you have that judge). That list is the job's contract. - Stay off
api.legacy. If a snippet you copied still saysobservations_v2orapi.scoresv2, replace it withapi.observationsandapi.scores_v3/api.scoresV3before you schedule anything.
Own the read path, then worry about what you send
There is one project API, Basic Auth, and a typed api namespace on the v4 and v5 SDKs. Observations, scores v3, and metrics are the defaults. Expect a short ingest lag. Harbor Desk's nightly job pulls low-score tickets. Blob export is how the warehouse gets the rest.
The data was always yours. The UI was never the only door. Once you can pull yesterday's failures into a queue without clicking, the next questions are about what you send: masking, sampling, flush on shutdown, retention, and whether you stay on Cloud or run the same architecture yourself. Those are production decisions. They are easier once the read path is a script you already trust.