What We Receive
Updated
Asqav signs a record of each action your agent takes. To do that it needs a fingerprint of the action, not the action itself. When the SDK talks to the Asqav cloud (api.asqav.com), it hashes the action context on your machine and sends the hash plus a short list of labels. Your prompts, the messages your agent exchanges, tool arguments, file contents, model output and any secrets in the context stay with you.
This page lists every field that leaves your machine, what stays local, how long we keep what we receive, and three ways to check all of it yourself.
How it works
- Your code calls
agent.sign("tool:read_file", context). The context can hold anything: the prompt, the file, the tool's arguments. - The SDK turns the action type and context into canonical JSON and computes its SHA-256 hash locally. If you set an
org_salt, the hash is HMAC-SHA-256 keyed by a salt only you hold. - The SDK sends the hash, the byte length of the canonical context, and the labels in the table below. The context itself is not in the request.
- Asqav signs that record with ML-DSA-65, links it to the previous receipt and returns the signed receipt.
The SDK picks this hash-only mode automatically for any *.asqav.com address. The cloud enforces it too: a sign request that carries a raw context is refused with 400 MODE_NOT_ALLOWED unless your organisation has signed a separate agreement to store full payloads. Metadata keys outside the allowed list are dropped on arrival.
What is sent
| Call | Fields sent | Notes |
|---|---|---|
POST /agents/{id}/sign and /sign-batch | action_type, hash, hash_algo, payload_size, session_id, nonce, metadata | metadata holds only agent_id, session_id, action_type and, if you opt in, model_name, tool_name, parent_id. nonce is random. |
| Same call, when you pass a result | result_digest | A SHA-256 of the result, computed locally. The result is not sent. |
| Same call, receipt fields | receipt_type, policy_decision, action_ref, plus any optional field you pass by name | action_ref is a digest. Optional fields (for example reason, risk_class, repo_ref, commit_sha) are sent only when your code sets them, and are stored as you wrote them. |
POST /agents/create, GET /agents/{id} | Agent name, algorithm, capabilities | Names you choose for your agents. |
POST /sessions/ and session updates | agent_id, session status | Groups receipts. No content. |
| Suspend, revoke, emergency halt | The reason string you pass | Only when you call these. |
POST /audit-pack/export | Time window, optional agent_id | Downloads your receipts. |
GET /.well-known/jwks.json | Nothing | Fetches public verification keys. |
| Every request | X-API-Key header, User-Agent with the SDK name and version | Our servers log the source IP and user agent for security, as the privacy policy describes. |
The action_type label travels in clear text, so keep it a category such as tool:read_file or llm:call. Do not put a prompt, a query or a customer name in it. The same goes for agent names and any optional field you choose to set.
What stays on your machine
- Prompt text, system prompts and chat messages.
- Tool arguments, including full shell commands and their values.
- File contents and anything else you put in the action context.
- Model output and tool results. Only their hash is sent.
- API keys, tokens and passwords that appear in the context.
- Your
org_salt. We never receive it and cannot recover it. - The offline queue (
~/.asqav/queue). Queued actions keep their context on your disk; syncing sends the hash, the same as a live sign.
Self-hosted deployments run the signer on your own infrastructure, so nothing reaches Asqav at all.
How long we keep it
- Signature records: for your plan's log retention period, listed on Pricing. Enterprise retention is set in your agreement.
- Signing in compliance mode, or declaring a regulated regime, raises the floor to at least 184 days, and longer where a regime requires it. The regime-by-regime table is on Data Handling.
- Account deletion requests to info@asqav.com are completed within 30 days. A hash already anchored to a public timestamping service cannot be withdrawn, but that anchored value is a digest over the signed receipt, not over your context.
- The server is backed up daily in the EU (Hetzner, Germany).
Check it yourself
1. Run our egress test. The public asqav-sdk repository has a test that plants a prompt, a file body and a secret-shaped key in the context, runs every signing path against the cloud address, captures each request on the wire and fails if any planted value appears. A second run in full-payload mode must leak, which proves the check works.
git clone https://github.com/jagmarques/asqav-sdk
cd asqav-sdk/python && pip install -e ".[dev]"
pytest tests/test_no_sensitive_egress.py
cd ../typescript && npm ci && npx vitest run tests/noSensitiveEgress.test.ts2. Watch the real request. Point the SDK at a listener on your machine and read what arrives. Set ASQAV_MODE=hash-only, because a non-Asqav address would otherwise default to full payload.
nc -l 8080 &
ASQAV_API_KEY=sk_test_local ASQAV_MODE=hash-only ASQAV_API_URL=http://127.0.0.1:8080 python3 -c '
import asqav
asqav.init()
asqav.Agent("agt_1", "demo", "pk", "kid", "ml-dsa-65", [], 0.0).sign(
"llm:call", {"prompt": "my secret prompt"})'The body nc prints carries a hash and no prompt. The Python call then fails because nc sends no reply, which is expected.
3. Recompute the hash. The hash on a receipt is SHA-256 over the canonical form described in the fingerprint spec. Recompute it from the context you kept and compare. A match shows the receipt covers your action, without the action ever leaving your systems.
One limit to know
An unsalted hash of a predictable action can be guessed by someone who holds the hash and can try candidate values. For contexts drawn from a small set, set an org_salt at asqav.init(). Data Handling explains the trade-off.