A no-logs LLM API: what is stored, what is not, and how to check

Every usage row, hash and ledger entry one request writes here, the bodies it never writes, and three checks you can run on your own responses: a signed receipt, an opt-out header and the request id.

·UplinkSwitch·All posts

Every provider page on page 1 for no logs LLM API says it keeps no prompts. None shows you how to check. This post lists what one request to UplinkSwitch writes, field by field, what it never writes, and three checks you can run on your own responses: a signed receipt, an opt-out header, and a request id that returns a record with no body in it.

One honest line first. A gateway cannot prove a negative to you. It can publish exactly what it stores, sign the figures it bills from, and return records you can inspect. The privacy page is the full list; this post is the request-level view of it, with one live request made on 2026-10-19 23:33 UTC as the worked example.

What a no logs LLM API writes per request

Here is the complete set of records one chat request leaves behind. It is the privacy page restated per request, with the retention period on each row.

RecordWhat it holdsKept
Usage rowRequest id, model, host, mode, token counts by class, the source of those counts, the chargeAs an accounting record, after the account closes too
Ledger entryBalance changes: top-ups, charges, refunds, disputesAs an accounting record
Request and response fingerprintsSHA-256 of the request body as sent and of the response body as relayed, so a receipt can be signedWith the usage row
Large system prompt fingerprintSHA-256 of a long shared prefix, to cache prompts many accounts send. Never the text7 days
Request bodyThe prompt and the completionNot written, unless replay is on for the key: then 7 days
API keyA salted hash, the key name, status, limits, timestampsWhile the account is open

From the privacy page, last updated 2026-10-18. Account rows (checkout email and amount, first-visit referrer) are per account, not per request, and are on the same page.

Three things to take from the table. Usage metadata is kept, and it is kept as an accounting record: model, token counts, charge. A fingerprint is a one-way hash, so a stored SHA-256 lets you prove a body matched a receipt and lets nobody read it back. And the body itself has one path to disk: replay, which you turn on per key and which keeps that key's request bodies for 7 days so a logged request can be sent again to another model.

The content does leave the gateway once, by design. The model that answers runs with a model hosting provider under contract with UplinkSwitch, and that provider receives the request and response content for the call. In bring-your-own-key mode the request goes to Anthropic, OpenAI or Google on your own account instead. Neither path writes the body here.

Check 1: read the signed receipt on your own response

Every non-streamed answer carries an x-uplink-receipt header. It is a base64url payload, a dot, then an Ed25519 signature. The payload names the model that answered, the tokens billed in each class, the charge, and the SHA-256 of your request and of the response. It never contains the text.

This is the request made for this post, with the key in an environment variable. It prints the response headers that start with x-uplink- and drops the body:

shell
curl -s -D - -o /dev/null https://api.uplinkswitch.com/v1/chat/completions \
  -H "Authorization: Bearer $UPLINKSWITCH_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-uplink-crowd-cache: off" \
  -d '{"model":"glm-5.3-flash-uncensored","messages":[{"role":"user","content":"Reply with the word ok."}],"max_tokens":16}' \
  | grep -i '^x-uplink-'

Sent 2026-10-19 23:33 UTC to glm-5.3-flash-uncensored with max_tokens 16. What came back, by header name:

HeaderShape of the value
x-uplink-request-idul_ prefix, 27 characters
x-uplink-modelglm-5.3-flash-uncensored
x-uplink-charge0.000007
x-uplink-receipt669 characters, one dot
access-control-expose-headersThe x-uplink- names above, so a browser client can read them too

Observed on 2026-10-19 23:33 UTC, HTTP 200. The request sent x-uplink-crowd-cache: off and the response carried no x-uplink-crowd-cache header.

The same receipt is also served as JSON for any request, streamed or not, once the request reaches the log (about a minute):

shell
curl -s https://api.uplinkswitch.com/v1/requests/$REQUEST_ID/receipt \
  -H "Authorization: Bearer $UPLINKSWITCH_API_KEY"

For the request above that returned an object with the keys payload, signature, alg, key_id, public_key_url, receipt. The receipt object read: model glm-5.3-flash-uncensored; billed tokens 13 input and 14 output; charge $0.000007; refund null; then request_sha256 and response_sha256, 64 hex characters each.

To check it, paste the header value or the JSON into the receipt verifier. It fetches the public key from GET /v1/statements/public-key, matches the key_id (an RFC 7638 thumbprint), and checks the signature with the browser's SubtleCrypto.verify. Nothing is uploaded and no account is needed, so your own users can verify a receipt you hand them. Hash the request body you sent and compare it with request_sha256: a match proves the receipt is for your bytes, and it proves it without anyone holding those bytes.

The Python version, with the OpenAI SDK's raw response so the headers are readable:

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.uplinkswitch.com/v1",
    api_key=os.environ["UPLINKSWITCH_API_KEY"],
)

raw = client.chat.completions.with_raw_response.create(
    model="glm-5.3-flash-uncensored",
    messages=[{"role": "user", "content": "Reply with the word ok."}],
    max_tokens=16,
    extra_headers={"x-uplink-crowd-cache": "off"},
)
completion = raw.parse()
request_id = raw.headers["x-uplink-request-id"]
receipt = raw.headers["x-uplink-receipt"]  # base64url payload, a dot, the signature
print(request_id, completion.choices[0].message.content)

Check 2: opt a request out of prefix fingerprinting

The one place a prompt-derived value is kept beyond the usage row is the crowd cache. A large system prompt that at least 3 organizations send within 7 days gets a cache breakpoint on Anthropic-format requests, so everyone's cached reads bill at the cached rate. To find those prompts the gateway keeps a SHA-256 of the prefix for 7 days. No prompt text, only the hash.

If you do not want even the hash, send x-uplink-crowd-cache: off on the request. That request is not fingerprinted for caching. When a breakpoint was applied the response says x-uplink-crowd-cache: on, so a response with no such header, like the one above, tells you no crowd breakpoint touched it. A request that sets its own cache_control is left alone either way.

The receipt fingerprints are separate and are not optional: they are what the signature covers, and without them a receipt could not show what was billed.

Check 3: the request id returns a record with no body

Every response, errors included, carries x-uplink-request-id. Look it up with any key of your organization:

shell
curl -s https://api.uplinkswitch.com/v1/requests/$REQUEST_ID -H "Authorization: Bearer $UPLINKSWITCH_API_KEY"

On 2026-10-19 23:33 UTC the record for the request above had these keys and no others: charge_usd, created_at, id, key_id, latency_ms, list_cost_usd, model, object, outcome, refund, saved_usd, status, usage. That is the usage row from the table, with timings. There is no messages field, no prompt field and no completion field, because the row never had them. A request id from another organization is not returned.

Log the id with every call. It is the handle for a support report, for the receipt endpoint, and for the monthly statement, where the CSV has one row per request under the same id.

Zero data retention LLM API claims, as others publish them

Three pages from the same results set, read on 2026-10-19. Their strengths first, in their own terms, and what each leaves for you to check.

ProviderWhat the page saysHow you check it
OpenRouterPer-request zdr: true routes only to endpoints with a zero-retention policy; data_collection: "deny" skips providers that store data. Both exist as account-wide settings too. Its privacy policy (updated 2026-08-31) says it does not train on inputs or outputs.A routing filter on the request. The policy gives no retention period for its own logs.
VeniceDoes not store or log prompt and response content for normal inference; Private mode is zero retention by contract. Operational metadata (model, token counts, request ids, IP) is processed for billing and abuse prevention.Contractual. The page names no check a caller can run.
trustedrouterNo prompt or output content logged; usage metadata kept separately. TEE routes run in an attested enclave with a published image digest.An attestation endpoint the caller queries with a nonce. See their page for the method.

Read 2026-10-19. OpenRouter: provider routing docs and privacy policy. Venice: API privacy docs. trustedrouter: the no-log page. None of the three docs pages shows a last-updated date; the OpenRouter policy does.

OpenRouter's routing parameters are the most useful of the three for a developer, because they are a request-level switch you can test. Its ad on the results page for this query on 2026-10-19 read “zero data retention by default”; the docs read the same day say zdr has no effect on routing unless you send it or set it on the account, so set it. Its privacy policy says it may re-identify stored inputs with a user id for debugging and keeps data as long as reasonably necessary.

Venice's API privacy page is the clearest statement of metadata among the three: it lists what the billing record holds and says it needs no prompt. That is the same position as the usage row here. Its stronger modes (TEE and end-to-end encryption) are a different product class.

trustedrouter goes furthest on hardware: an attested enclave is the one design where even the operator cannot read the prompt. The check is real and the reader can run it. What it costs per token is on their pricing page.

What none of the three gives you is a signed, per-request record of the billed tokens and the body hashes that a third party can verify offline. That is the receipt above, and it is the reason this post can show its own request instead of describing a policy.

A private LLM API: what you can verify and what you cannot

You can verify what a receipt says: the model name, the billed tokens, the charge, and that the hashes match your bytes. That closes the two questions a bill raises, which model answered and what you paid for. The daily real-model check runs the same kind of test from the outside, one fixed prompt to every model each UTC day, and the hidden prompt tokens post shows what that check finds on routes that pad the input.

You cannot verify, from the outside, that a body was never written. No API can show you the absence of a file. What a provider can do is narrow the question: publish the full list of records, make the only body-retaining feature opt-in per key, keep the fingerprint opt-out on a header, and sign the figures. Then the remaining trust is in the privacy page, and the page is specific enough to be wrong in a checkable way.

The same records apply to every model on the key, from Claude and GPT to the uncensored builds many readers of this query are after. Prices for all of them are in the LLM API pricing comparison, read from the live catalog.

Questions

How do I call a no logs LLM API from Python? With the OpenAI SDK: base_url https://api.uplinkswitch.com/v1, your key, and with_raw_response so the x-uplink-request-id and x-uplink-receipt headers are readable. The example above is the whole program. See the SDK setup guide.

Where do I get a no logs LLM API key? From the console after a prepaid top-up from $10. The key is shown once and stored as a salted hash; replay retention is off on a new key, so no request body is written until you turn it on. See the console.

Is there a no logs LLM API on GitHub? The verification side is public: the public key is at GET /v1/statements/public-key, the receipt fields are documented on the verifier page, and any Ed25519 library checks a receipt in a few lines. The gateway code is not on GitHub. See the verifier.

Which LLM is the most private? One running on hardware you control, with no network path out. After that, a hosted model whose operator writes no request bodies and says in its privacy page what it does write. A model name alone says nothing about privacy; the operator does. See what is stored here.

What is the difference between a no-KYC and a no-log AI API? No-KYC is about sign-up: what identity the provider asks for before selling you credit. No-log is about the request: whether the prompt and completion are written to storage. A provider can be either, both or neither. See AI API without KYC.

Does a no logs LLM API still keep usage metadata? Yes, every one we read does, and so does this one: a usage row per request with the model, token counts and charge, kept as an accounting record. A receipt and a monthly statement are built from those rows, never from the text.

Can I have my account data deleted? The console account page takes a deletion request, handled by a person. Usage records and ledger entries are kept as accounting records after an account closes, as the privacy page says.

Get a key: prepaid from $10, no subscription, 30-day price lock.

Price index and model launches, once a month. Unsubscribe in one click.