Legal
Privacy Policy
Agent Vault lets an AI agent check out and sign in on your behalf without ever holding your real card number, password, or one-time-code seed. Doing that means we hold those things instead. This page says exactly what we hold, who else sees it, how long it stays, and where our current implementation falls short of what we intend.
1. Who we are
Agent Vault is a product of Self.xyz, operated by [LEGAL ENTITY NAME], registered at [REGISTERED ADDRESS] (“we”, “us”). For data you store in Agent Vault we are the controller: we decide what is collected and why.
Privacy enquiries: [privacy@…]. Data protection contact: [DATA PROTECTION CONTACT]. Representative for EU/UK data subjects, where one is required: [EU/UK REPRESENTATIVE, IF REQUIRED].
This policy covers the Agent Vault web app and dashboard, the checkout proxy that fills forms on your behalf, and the backend that stores your vault. It does not cover the merchant sites and login sites your agent visits — those are independent controllers with their own policies.
2. What we collect
Almost everything below is data you deliberately put in, because the product cannot fill a checkout form with data it does not have. We do not buy data, and we run no advertising and no third-party tracking. We do run product analytics on our own website — pageviews and a few product events, with no profile of you attached to them (see §13). We also keep our own operational telemetry about agent sessions — see below.
Account and identity
- Email address and account identifier, from our authentication provider when you sign in.
- First name, last name, and phone number, if you enter them, so an agent can complete a checkout’s contact fields.
- Your plan (Free, Plus, Pro), billing identifiers issued by Stripe, and your notification preferences.
Addresses
Full postal addresses you save — label, street lines, city, state/region, postal code, and country — used as shipping and billing addresses at checkout.
Payment cards
Your card number is sent from your browser directly to our card vault provider (see §5). For a card you add now, our database holds a vault token reference and non-secret card metadata: last four digits, brand, expiry month and year, the cardholder name you enter, and a link to the billing address you chose. Legacy rows from the pre-vault design can still carry encrypted card data until the purge job clears them — §5 has the detail.
We do not store the card security code (CVV/CVC) for cards added now. When a merchant demands one, we ask you for it at the moment of the purchase; it is never written to our database, and lives only in the proxy’s memory for that session (§5). A column holding security codes under the previous design is still being purged (§5).
Site logins
For each site you connect we store a label, the site URL, an optional note, the username, the password, and, if you add one, the seed for time-based one-time codes (TOTP). The password and the TOTP seed are encrypted at rest; the username and site are stored in readable form so the dashboard can list them.
Agent configuration
Agent cards and API keys you create, including their names, spending limits, merchant allowlists, usage counters, and any webhook URL you configure. An API key you create today is stored as an irreversible hash — never the key itself — alongside the first few characters of it, so the dashboard can show you which key a row refers to.
An older agent card, created under a design that has since been replaced, may still carry a proxy credential of its own on the record. Those columns are no longer written, and a data export strips them — but the dashboard’s own listing does not, so on such a card that value is still sent to your browser along with the rest of the record. It is your own credential rather than anyone else’s, and only you can fetch it. Until those columns are purged we will not claim we hold no key material anywhere, nor that it stays server-side. Stripping those columns from the dashboard listing, and then purging them, is tracked as issue #213.
Activity records
- A per-session audit trail of what your agent did: the merchant host, which API key was used, start and end times, navigations (host only), which kinds of token were filled, denials and their reasons, any challenge the session ran into (its kind, and whether it was handed to you and completed), and the outcome. No value the proxy substitutes — card number, security code, password, or identity field — is ever written to this trail.
- Operational telemetry about the sites your agent visits. As your agent navigates, our proxy classifies each navigation — was it blocked, did it hit a challenge, why — and does two things with that. It keeps a running per-merchant tally in memory, which is what we read to see which merchants are breaking. It also writes one line per navigation into our server logs, recording the merchant host, the classification and the time.
- To make that classification, the proxy reads a bounded sample of the page’s visible text — the title and up to a few thousand characters of body text — and passes it to a detector that looks for the signatures of a block wall or a bot check. On a checkout or account page that sample can contain whatever the merchant has rendered, including your own details. It is used and dropped: it is never written to the log line, the audit trail, our database, or anything your agent can read. We would rather describe it than let “the telemetry holds nothing of yours” stand in for “nothing of yours is ever looked at”.
- What is kept from all this is about the site, not you: the tally and the log line carry no account identifier, no session identifier, and nothing you stored. But the log line is a log line — it lands in our hosting provider’s logging infrastructure like any other server log (§8), so “it goes nowhere” would be wrong. It is analytics, and we would rather name it than let “we run no analytics” imply we measure nothing.
- A redacted screenshot of a confirmation page, stored as a session receipt, and a redacted screenshot attached to an approval request when your agent pauses for your sign-off. Receipts are captured under a fail-closed rule, applied at the moment of capture: if the proxy has substituted any sensitive value by then — on that page, an earlier page, or another tab — no receipt is stored. A later confirmation in the same session that captures nothing also clears an earlier one. What this does not do is reach back: a receipt taken from a genuinely clean checkout stays stored even if the same session goes on to fill a token afterwards and never records another outcome.
- A record of each prompt we send you when an agent pauses. An approval request stores the agent card’s name, the merchant host, the amount and your threshold, the reason, the decision and who made it, and the redacted screenshot above. A security-code prompt stores the merchant host and your card’s last four digits — never the code you type. A challenge handoff stores the kind of challenge that was hit (a bank prompt, a one-time code, or a CAPTCHA), the merchant host, and the permission to attach to one paused session — but no challenge response, no one-time code, and no frame of the stream. Each also records which API key the paused fill belonged to for a security-code prompt, and for a challenge the specific proxy session and page being handed over — so those tie back to the agent that raised them. A purchase approval records no key or session, so it identifies the agent card and the merchant but not which key was in use. Each holds the token from the link we email you, which is never returned to your agent. All three links expire within minutes of being sent — the exact window is set per request, because it has to fit inside the paused agent session waiting on you. An approval or security-code token is additionally spent once it is used; a challenge-handoff token is not, and stays usable for its whole window so that a dropped connection can reconnect (§7).
- One caveat on those links: an approval link is written to our operator logs when a purchase is held, and — if our deployment has one configured — is also sent to an operator approval endpoint (§8). Both are deliberate fallbacks, so a held purchase can still be released if email delivery fails. Both mean the link that can approve or deny that charge leaves the email channel: into our internal logs, and possibly to an operations endpoint, until it is used or expires. Security-code and challenge links are not distributed this way.
- Transaction records — merchant host, amount and currency, a US-dollar conversion, any amount your agent declared, the outcome and, for a refusal, the reason — for spending limits, approvals, and your activity feed. Each row also links the fill back to the funding card, the agent card whose controls governed it (and any cards credited for it), the API key used, and the proxy session, so an entry in your activity feed can be traced to exactly which agent did what.
- Notification records: for every alert we send you, its title and body, the agent card and API key it concerns, whether the email was sent, and a structured copy of the event details — which, depending on the alert, can include the merchant host, your card’s last four digits, the spending threshold that was crossed, the kind of challenge encountered, and the label of the key involved. Also delivery logs for webhooks you configure: the destination URL, the signed body and its signature, plus the attempt record — delivery status, how many attempts were made, the last HTTP status code or network failure reason, when the next retry is due, and created/updated timestamps. One alert carries network detail the others do not: when a session’s traffic leaves our datacenter instead of being relayed through your machine, the untunnelled-egress alert stores the proxy session id, up to five of the destination hosts that were reached, how many hosts and connections were involved, whether any of it was unencrypted, and which route was used instead. A session that used an attested checkout — a path that is not in service today (§5) — records a second list the same way — up to five merchant hosts the enclave itself connected to, how many there were, and whether that count was truncated — so a mixed session can retain up to ten hosts across the two lists. Like the rest of your notification history, those rows are retained after account closure (§10).
- If you turn on background alerts — the option that reaches you when the dashboard is closed — we store the push subscription your browser issues: its endpoint URL and the encryption keys needed to deliver to it, plus a coarse device label derived from your browser (“Chrome on macOS”, so you can tell your devices apart in Settings) rather than the raw user-agent string. Each row also keeps delivery bookkeeping: when it was created, when the push service last accepted a message, and how many consecutive failures it has seen, so a permanently broken endpoint can be pruned. The separate in-page desktop-notification toggle stores nothing on our side; it is the device-local flag described in §13.
Technical data
Our servers process the usual request metadata (IP address, user agent, timestamps) in order to serve and secure the service. Our hosting and backend providers keep operational logs on our behalf.
Those logs also carry application identifiers, not just network metadata: every successful agent connection records its proxy session id, and a refused cross-account token attempt records both the account the value belongs to and the account whose session asked for it. They are pseudonymous — no card number, password or code is ever logged — but they can be linked back to your account and session records, and they persist in our hosting provider’s logging stack on its own retention schedule rather than ours.
Our own demo pages
This site hosts two demonstration checkouts — a sample merchant page, and one that uses Stripe’s own card field — so you can watch the token substitution happen. They are toys, but they are ours, and that changes who receives what.
- If an agent completes our sample checkout, the submitted values reach our web server rather than an independent merchant. In production they are handled to produce the response and not stored. Outside production — a preview or local build — the last submission is also kept in memory and readable back, because the end-to-end tests need to assert on it, and the first name, last name, street and the card’s last four digits are written to the server log for that build. Log entries outlive the in-memory value and are kept by our hosting provider, which is another reason to point a demo at a test card.
- The Stripe demo loads Stripe’s script into the page and tokenizes the card directly with Stripe, so Stripe receives whatever card details are entered there, plus your IP address and user agent. That is separate from our subscription billing (§8) and from a merchant’s own processor (§4).
Point a demo at test cards, not a card you rely on. The whole site is a preview, and these two pages are the part of it most likely to surprise you about where a value ends up.
3. Why we use it, and our lawful basis
Where the GDPR or a comparable law applies, these are the purposes we process your data for and the legal grounds we rely on.
| Purpose | Data used | Lawful basis |
|---|---|---|
| Run your account and vault | Account, identity, addresses, cards, logins | Performance of our contract with you |
| Let your agent complete a checkout or sign-in | Card token, addresses, identity fields, credentials | Performance of our contract, at your instruction |
| Spending limits, approvals, and fraud prevention | Transactions, session audit trail, agent-card settings | Contract, and our legitimate interest in preventing misuse |
| Show you what your agent did | Session audit trail, receipts, transactions | Contract, and your legitimate interest in oversight |
| Alert you to approvals, security codes, and handoffs | Email address, notification content, push subscription | Contract; consent for browser push notifications |
| Billing for paid plans | Email address, plan, Stripe identifiers | Contract, and our legal obligation to keep tax records |
| Keep the service secure and available | Technical and operational log data | Our legitimate interest in the security of the service |
You can withdraw consent for browser push notifications at any time from your browser or the dashboard; that does not affect processing carried out beforehand.
4. How agents and the proxy use your data
This is the part of the product that most affects your privacy, so it is worth stating precisely.
- Your agent is issued mock tokens — placeholder strings such as
SAPu7x2kc1000000. It types those into forms. The agent, its model context, its logs, and anything it sends to its own model provider contain the mock token and never your real card number, security code, or password. The catalog it fetches carries more than the tokens, though, and that travels the same path: your internal account id, the labels you gave your addresses and logins, each login’s site reduced to a bare host and whether it has 2FA, and for each card its brand, last four digits and full expiry month and year. Where a card is governed by an agent card in allow-list mode, the catalog also carries that allow-list’s merchant hostnames — the sites you decided that agent may spend at, which says something about you that the other fields do not. All of it is what a human needs to tell one saved item from another, and your agent needs the same; but it reaches the agent’s context and its model provider alongside the tokens. - The real values are substituted by our checkout proxy, which drives a browser that runs on our infrastructure. To be clear about what your agent can do with that browser: it does drive it — it navigates, clicks, and types through our SDK, and it can take screenshots, which we redact before returning them. What it cannot do is read the page’s contents directly (script evaluation is refused) or read back any real value the proxy substituted. So your agent controls the session and sees a redacted view of it, and no interface hands it a stored value. One gap we would rather state than gloss, and how it closed: because your agent drives a real keyboard, it could once send editing chords — select-all, copy, paste — to a field the proxy had already filled and carry that value elsewhere without ever reading it back through our API. Once a session has had a real value substituted into it, the proxy refuses every modifier chord that could reach the clipboard, with a stable “clipboard blocked” error. Ordinary typing, Tab, Enter, Escape and the arrow keys are unaffected, and three navigation shortcuts stay allowed by name — Shift+Tab, Alt+Left and Alt+Right — because they cannot copy anything. The rule is deliberately broad rather than a list of blocked shortcuts, because every list we wrote had another spelling past it (issue #252). So we keep your secrets out of your agent’s view and out of its clipboard — in a session it otherwise fully controls. The proxy resolves a mock token to a real value only after our backend has authorised that specific fill. Every kind of value is checked against a live, non-revoked API key that belongs to your account — with one exception, a challenge-handoff page already open when the key is revoked (§12, issue #212). A security-code prompt is not an exception: the card is re-authorised after the code arrives, so revocation stops it. Login fills are additionally locked to the site the credential was saved for. A card-number fill is additionally checked against merchant policy, spending limits, and any approval you require — but only when an agent card governs that card; a card filled directly, with no agent card linked to it, is subject only to your plan’s account-wide cap on the NUMBER of payments in a rolling 30-day window (2, 10 or 30 depending on tier) — a count, not an amount, so it bounds how often such a card can be used and never how much it spends. If you want a card governed, put it behind an agent card.
- A security code on its own is checked, but not counted. When a saved-card checkout asks only for the security code and never for the number, that fill still runs the key, account, pause and merchant checks, and it can still pause for your approval — the code is as sensitive as the number, so it is gated the same way. What it does not do is consume your spending limits or record a transaction: those happen on the card-number fill, so that a card and its code together count once rather than twice. The practical consequence is that a code-only checkout can be stopped by a pause, an allowlist, or an approval, but it is not bounded by your spending limits.
- The merchant or login site receives the real value, because that is the point: a real purchase needs a real card number, and a real sign-in needs a real password. Once submitted, that data is governed by the receiving site’s own privacy policy, not this one.
- Often the merchant’s payment processor receives the card, not the merchant. Many checkouts embed card fields hosted by a payment provider — Stripe, Adyen, or similar — in a frame belonging to that provider, and our proxy fills those frames directly. Your card number, its expiry, and the security code you enter for that purchase then go to that provider under their privacy policy and the merchant’s agreement with them. We have no relationship with them and do not choose them; the merchant does. (This is separate from the Stripe entry in §8, which covers only our own subscription billing.)
- The proxy browses whichever sites your agent directs it to, and those sites see whatever your agent submits.
- By default they also see your own IP address, not ours. When an agent runs through our SDK, the proxy relays the browser’s network traffic back to the machine running your agent and dials the merchant from there — so the merchant sees your network, typically a residential IP. This is deliberate: a datacenter IP is a strong bot signal that blocks many checkouts. It does mean your IP address is disclosed to every site your agent visits. One path is an exception. A default session prefers the relay rather than requiring it, and an attested checkout runs the merchant page in a separate hardened browser that cannot use the relay the way your own agent’s browser does — so on that path the merchant sees our datacenter address, not yours, even with default settings. Only a session that requires the relay (
tunnel: true) is refused rather than allowed to proceed that way. That path is not in service today and is refused before it runs (§5); it is described here so the disclosure is already right if we do turn it on. The hosts it reached are recorded and disclosed to you (§2). We have since built a relay that carries the hardened browser’s traffic back through your machine too, which would remove this exception — but it is not enabled in any environment, so the datacenter address above is what would happen today. Passtunnel: trueif you need the relay to be mandatory rather than preferred. For anhttps://site — which is every real checkout — the relayed bytes are TLS-encrypted and your machine cannot read them. On a plainhttp://page we now refuse the fill: no card number, security code, password or identity value is substituted into a page that is not TLS-protected, and the agent is told the page is insecure. Such a page is also no longer relayed through your machine — plaintext traffic leaves from our datacenter instead — so it cannot put anything of yours on your own network in the clear. You can turn the relay off (tunnel: falseorSELF_AGENT_PAY_TUNNEL=0), in which case sites see our proxy’s datacenter IP instead; the same happens automatically if the relay cannot be established.
5. Card data specifically
Card numbers are held by Basis Theory, a PCI-DSS Level 1 certified tokenization vault, and not in our own database. When you add a card, the number is typed into an input hosted by Basis Theory inside your browser and sent directly to them; we receive back an opaque token reference and store that. The write path rejects anything that is not a vault token identifier, so no card number added today can land in our database.
If adding a card fails after that step — a validation error, or a network failure while saving the rest of the record — the card is already in the vault and we end up with no reference to it. Nothing in our system then points at it, which also means our own deletion tooling cannot find it. Tell us if a card save failed and you want it removed; until then it sits in the vault unreferenced. Cleaning those up automatically is tracked as issue #214.
For completeness: our database schema still defines columns that held encrypted card numbers, and one that held encrypted security codes, under the design that preceded the vault. No code writes any of them any more, and scheduled jobs purge the remaining pre-vault rows so the columns can be dropped altogether. Until that finishes, we would rather tell you the columns exist than claim a schema that cannot hold a card number.
Where the number is revealed. To type your card into a merchant’s checkout form, something has to turn the token back into digits. Today, wherever card filling works at all, that happens inside our checkout proxy process — there is no configuration in which some other component reveals it: the proxy calls the vault, holds the number in memory, and types it into the merchant page. It is not written to our database, our logs, or the session audit trail. A deployment that is not configured to fill cards refuses the fill outright, before any number is retrieved; that is the only other outcome.
Our software also contains a second path — the attested checkout of §4 — which hands the vault token to an isolated, attested enclave that reveals the number and types it in its own browser, so that not even we can see it. We are describing code, not a service you can use. On this hosted service no such enclave is deployed, so an attested checkout here is refused before any card is handed over. (The path can be exercised elsewhere — a developer running our software can point it at an enclave of their own — but that is someone else’s deployment, not this one, and this policy describes only this one.) So the paragraph above is what happens to your card, and it will stay that way until we say otherwise here. We do not claim the enclave protection today.
How long it stays in memory. Not just the moment of typing: once a value has been filled, the proxy keeps a copy in that session’s memory until the session ends, so it can recognise and blank out the value if it would otherwise appear in a screenshot or an error message returned to your agent. The retention is what makes the redaction possible — the proxy cannot scrub a value it no longer holds — but it does mean the plaintext lives in proxy memory for the session, not for a single fill. It is never persisted anywhere. The same applies to a password or security code the proxy fills.
That in-proxy reveal is switched on only where the vault’s private key has been provisioned for the deployment. Without it, the proxy refuses every card fill outright rather than falling back to anything weaker, so your card number is never revealed anywhere — and your agent cannot complete a card checkout at all. The two are deliberately tied together, so a half-configured deployment cannot exist.
Parts of our marketing FAQ still describe the reveal as happening “solely inside our attested Confidential Space enclave” — an enclave that is not deployed — and say the number “never touches our servers”. Where those statements conflict with the paragraph above, this policy is the accurate one. Correcting that copy is tracked as issue #194.
Vault status. Our vault account with Basis Theory is currently an evaluation tenant, not a production plan. Basis Theory’s PCI-DSS Level 1 certification is theirs, and describes their vault; it is not a certification of Agent Vault, and we make no PCI, SOC 2, or ISO claim about ourselves. Treat this deployment as a preview and do not store a card you rely on.
6. Site credentials specifically
We store the passwords and one-time-code seeds for the sites you connect. There is no way for an agent to sign in on your behalf otherwise, and we would rather say so plainly than bury it.
- Passwords and TOTP seeds are encrypted at rest with AES-256-GCM. Records written under the current scheme use a per-record data encryption key, itself encrypted (wrapped) by a key-encryption key, and their ciphertext is cryptographically bound to your account so it cannot be decrypted in the context of another user.
- Older records may not have both of those properties. Credentials saved before the per-record-key and account-binding changes are still readable under the previous shared-key scheme, and ciphertext written before account-binding decrypts without that binding check. A record is re-keyed only when the secret itself is re-entered — editing a login’s site, username or note leaves the existing ciphertext exactly as it was. So retyping the password (and the one-time-code seed, if you use one) is the way to move an old login onto the current scheme; changing anything else will not do it.
- The key-encryption key is held by us, as an environment secret in our backend. It is not in a hardware security module or a third-party key-management service today. Our deployment prefers a dedicated key-encryption key, but where one has not been provisioned it falls back to the same secret used for legacy data — so the separation between the two is a deployment property, not something this page can promise. A sufficiently deep compromise of our backend environment could reach stored credentials, and we are not going to describe that risk as eliminated.
- Usernames, site URLs, and your notes are stored in readable form so the dashboard can list your connected sites.
- Decryption happens only in our backend, and only for a fill your agent is authorised to perform. What leaves the backend depends on the field. A password is passed to the proxy as plaintext for that fill. A two-factor seed is not: it is decrypted inside the backend, used there to derive the current six-digit code, and only that short-lived code is sent on — the seed itself never reaches the proxy, so a proxy session can never generate a future code from it. As with a card number (§5), whatever value does arrive is kept in that session’s memory until the session ends so it can be redacted out of screenshots and error text; it is never persisted. Neither is returned to the agent or written to the audit trail.
Many sites’ terms restrict credential sharing and automated access. Connecting a site is your decision and your responsibility — see the Terms of Service.
7. Session records and the live screencast
Every agent session produces an audit trail so you can see what was done in your name. It records the merchant host, the API key used, timings, which token kinds were filled, denials and their reasons, and the outcome — never a substituted value.
When a site raises a challenge the agent cannot pass (a CAPTCHA, a two-factor prompt), the session can be handed off to you. We email you a link; opening it streams a live video of the proxy’s browser to that page and relays your clicks and keystrokes back, so you can finish the step yourself.
- The link is the credential. The handoff page is deliberately outside the signed-in area, because you are usually on a phone where you are not logged in — so it authenticates on the token in the link alone, and does not additionally check that you are signed in. The token is not spent by being used once: it stays valid until the handoff expires or settles, so that a dropped mobile connection can reconnect to the same session. For that whole window, anyone holding the link can attach and take over the live checkout. Treat a handoff email like a password reset email.
- Those frames are unredacted pixels of the page in front of you. They are sent only to the one attached viewer socket, drawn to a canvas, and replaced by the next frame.
- No frame is stored. Screencast frames never reach our database, the audit trail, a receipt, our logs, or anything the agent can read.
- The token is issued for one specific session belonging to your account, expires, and admits only one viewer at a time. The proxy re-checks the session, page, and owning account before it attaches.
8. Sub-processors and other recipients
We do not sell your personal information and we do not share it for advertising. We use the following providers to run the service. Our own infrastructure runs in the United States; several of these providers operate globally distributed networks, so the precise processing location for each is [PROCESSING LOCATIONS PER PROVIDER], to be confirmed against each signed data processing agreement.
| Provider | Role | Data it receives |
|---|---|---|
| PostHog | Product analytics for this website | Pageviews as route templates, a small number of product events, a random device identifier, and the IP address and user agent that any web request carries. No person profile, and nothing tying the device identifier to your account |
| WorkOS | Authentication and session management | Email address, authentication identifiers and events; and, because signing in sends your browser to them, your IP address and user agent |
| Basis Theory | Card vault (evaluation tenant) | Your full card number and expiry, sent directly from your browser; the account identifier stamped on the token; and, because your browser makes the request, your IP address and user agent |
| Stripe | Subscription billing and hosted billing portal, plus our Stripe demo page | Email address, account identifier, and the subscription and payment details you enter on Stripe’s pages. Subscribing and opening the billing portal send you to a page Stripe hosts, so Stripe also receives your IP address, user agent and request timing on those visits — not only on our Stripe demo (§2), where it additionally receives whatever card details are entered |
| Resend | Transactional email | Recipient email address, notification subject and body, and bearer action links — for approvals, security-code prompts, and challenge handoffs. A handoff link opens the live view of your checkout (§7), so Resend handles a credential, not just a notification |
| Convex | Application backend and database | Everything described in §2 that we store |
| Google Cloud (GKE, Secret Manager, Cloud KMS) | Hosting, secret storage, key management | Data in transit through our services; encryption keys; operational logs |
| Google Fonts | Web fonts, loaded on every page including pages you can view signed out | Your IP address and browser user agent when the page loads |
| Your browser vendor’s push service | Push delivery (Google, Mozilla, Microsoft, or Apple, depending on your browser; Safari and iOS route through Apple) — only if you enable it | Your push endpoint and delivery timing. Notification content is encrypted to your device and is not readable by the push service |
| Merchant and login sites you direct an agent to | Not our sub-processors — independent recipients | Whatever your agent submits, including real card and credential values |
| The merchant’s payment processor | Not our sub-processor — chosen by the merchant, e.g. Stripe or Adyen (§4) | Your card number and expiry, and the security code you enter for that purchase, when the checkout embeds their card fields |
| A webhook endpoint you configure | Not our sub-processor — an integration you choose, on paid plans; only if you set one up | A signed JSON payload for each notified event: its id and type, the agent card it concerns, and the non-link event details. Action links are not included |
| An operator approval endpoint, if our deployment configures one | Not our sub-processor and not chosen by you — an optional operations integration on our side, off unless configured | When a purchase is held: your account identifier, the name you gave the agent card, the merchant, the amount and your threshold, the expiry — and the approval link itself, which can release or deny that charge |
We also fetch daily currency reference rates from a public exchange-rate API in order to check foreign-currency totals against your limits. That request is made by our server and contains no personal data.
We may disclose data where we are legally required to, or to establish or defend legal claims. If we are ever involved in a merger or acquisition, your data may transfer as part of that transaction; we would tell you before it became subject to a different policy.
9. International transfers
Our infrastructure runs in the United States, and the providers in §8 are US-headquartered, though several operate globally distributed networks. If you are in the European Economic Area, the United Kingdom, or Switzerland, using Agent Vault means your data is transferred to the United States.
The transfer mechanism we rely on for each provider — Standard Contractual Clauses, the EU – US Data Privacy Framework, or another lawful basis — is [TRANSFER MECHANISM PER PROVIDER], to be confirmed against each signed data processing agreement. Ask us at [privacy@…] for a copy of the relevant safeguards.
10. Retention — and what deletion does not reach
This section describes what our system does today, including where it falls short of what a reader would reasonably expect. Each shortfall names its tracking issue.
Automatic deletion that does happen
- The session audit trail — session rows, their events, and their receipts — is purged 30 days after a session starts, on every plan. An hourly job does this.
- The card security code is not written down for any purchase made now, so there is nothing to expire — apart from the legacy column still being purged (§5).
- Screencast frames from a handoff are never stored, so there is nothing to expire.
Data kept until you delete it
Your account, addresses, card references, logins, and agent cards are kept for as long as your account exists. Approval requests, security-code prompts, challenge prompts, webhook delivery logs, and push subscriptions currently have no scheduled expiry and are otherwise kept until account deletion.
One exception, in your favour: a push subscription is deleted as soon as the browser’s push service tells us it is dead (an HTTP 404 or 410 when we try to send). So a subscription for a browser you no longer use does get cleaned up automatically — just not on a timer. Every other row in that list waits for account deletion.
To be clear about what that means for a prompt: the link we emailed you stops working within minutes (§2), but the record of the prompt is not deleted on any schedule. Nothing expires it. What that record holds differs by prompt, and only the first is a record of a decision about money:
- An approval request keeps the agent card, the merchant, the amount being approved, your decision, and — where one was taken — a screenshot of the checkout.
- A security-code prompt keeps the card’s last four digits, the merchant, and the status and timing. No amount, no decision, no screenshot, and never the code itself.
- A challenge handoff keeps which kind of wall was hit, the session and page it paused, and the status and timing. No amount, no decision, no screenshot.
Your notification history, your transaction history, and your API key records have no automatic expiry either, and — unlike the records above — they are not removed by account deletion. An API key is marked revoked and its row kept, not erased. See below.
There is no defined retention period for any of the records in this subsection. They are kept indefinitely, until either you delete your account (for the first group) or we adopt a retention policy and implement the job to enforce it. We are not going to state a number we do not enforce. Setting that policy is part of issue #106; the absence of any cap on the transaction table is separately tracked as issue #175.
What account deletion removes
Deleting your account removes your cards’ records, logins, addresses, agent cards, pending approval and security-code and challenge prompts, webhook delivery logs, push subscriptions, and your user record, and revokes every API key so in-flight agent sessions immediately stop resolving tokens.
It does not, however, terminate a proxy session that is already running. Revocation stops that session obtaining any further real value the moment it lands, but the browser it already has stays up until the session ends by itself or hits its one-hour ceiling, and whatever was already typed into the page can still be submitted. Deletion is therefore not an emergency stop: stop a running agent before closing your account.
What account deletion does not remove
Your card number is not removed from the vault when you delete your account. Deletion is supposed to instruct the vault to destroy the stored card, but that instruction is routed through a service that is not deployed in any environment, so it is silently skipped every time. Your card row is deleted; the card itself remains stored at Basis Theory until it is removed by hand. We will not tell you we delete your card data when we currently do not. If you want the card destroyed, email [privacy@…] and we will action it manually.
The skipped attempt is written to our operational logs with the vault’s identifier for that card and your account id — deliberately, so an operator can find an orphaned card later and destroy it. It does mean that after deletion a reference to the vaulted card survives in our logs even though the database row is gone. That reference is what makes the manual cleanup above possible.
Deleting your account does not cancel a paid subscription. The Stripe subscription continues to bill, and because deletion removes your account it also removes the in-product route to Stripe’s billing portal. Cancel your subscription before deleting your account, or contact us.
This is not limited to paid plans. The moment you start a checkout we create a Stripe Customer carrying your email and account id, plus a Checkout Session — so anyone who has ever opened the upgrade flow, paid or not, leaves those records at Stripe after deletion. We do not delete them for you today; email[privacy@…] and we will action it.
Some records are deliberately retained after deletion: transaction history (kept for accounting, fraud, and dispute handling), agent session rows, their events, and their receipts (until the 30-day purge reaches them), notification history, and API key rows (revoked, but not erased). Whether and how the account linkage on these is scrubbed is an open policy decision.
Note that a retained receipt is a redacted screenshot of a merchant confirmation page (§2). Deleting your account does not delete it — only the 30-day session purge does. If you need one gone sooner, ask us.
Deletion also does not remove your identity record at our authentication provider. If you still have a valid browser session, loading the dashboard after deletion will create a fresh, empty account for the same sign-in.
And a notification email already queued when you delete can still be sent afterwards: the queued job carries the recipient and the message, and deletion does not cancel it. Any action link inside such an email is already dead — the record it pointed at was deleted — but the email itself may still arrive.
A retention period for the records we keep after deletion has not yet been fixed: [POST-DELETION RETENTION PERIOD].
11. Your rights and how to exercise them
Depending on where you live you may have the right to access your data, receive a portable copy, correct it, delete it, restrict or object to processing, and complain to a supervisory authority. We do not discriminate against you for exercising any of them.
Correction and day-to-day control
In the dashboard you can see a listing of what you have stored — your addresses, logins, cards and agent cards — and delete any of them; addresses, logins and agent cards can also be edited in place. Cards cannot: correcting one means deleting it and adding it again, as the paragraph below explains. Two things are kept but not listed there: a settled prompt (an approval you answered, a security-code or challenge request that was used or expired) stays in our records until you close the account, while the dashboard shows only the ones still waiting on you. Ask us under §11 and we will hand over the rest.
Your stored secrets are write-only there, deliberately: when the dashboard lists what you have saved it never receives a password, a TOTP seed, or a card’s vault reference — only whether a password and a code are set, and the card’s last four digits, brand and expiry. You can replace a secret but not read one back. If you need to know a value you stored, we cannot show it to you; recover it from the site it belongs to.
The one moment that differs is adding a card. Your browser is what talks to the vault, so it necessarily handles the reference the vault returns and passes it to us on the way in. After that it is never sent back out to the browser again.
Cards have no edit form — correcting one means deleting it and adding it again. API keys can be revoked in the dashboard; a revoked key stops working immediately, apart from a challenge-handoff page already open at that moment (§12, issue #212), and its record is retained rather than erased. Deleting an individual card removes our reference to it — but see the vault caveat in §10, which applies to deleting a single card just as it does to deleting your account.
Export and erasure
Account export and account erasure exist as backend operations, but there is no button for either in the dashboard, and — being worth saying plainly — no support tooling behind them either. Both are self-service functions that authenticate as you; there is no administrative version we can run on your behalf. Fulfilling an emailed request today means an operator doing it by hand against the database.
That does not reduce your rights, and we will honour a request to [privacy@…] within 30 days. It does mean the process is manual rather than a supported flow, and we would rather tell you that than imply a button exists. Building the real path is issue #106.
The export currently returns your profile (account identifier, email, first and last name, phone, plan, sign-up and onboarding timestamps, notification preferences), your addresses, your logins (label, site, note, username, and whether a password and a TOTP seed are set — never the secrets themselves), your cards’ non-secret metadata, your agent cards, and your API key records without the keys.
It does not include several things we nonetheless hold, so an export is not a complete picture of your account: your notification history and its stored event details (§2), webhook delivery logs, settled approval and prompt records, and your push subscriptions with their device labels and delivery bookkeeping. Deleting your account removes the webhook logs, the settled prompts and the push subscriptions — but not the notification history, which is deliberately retained (§10). Ask us under §11 for anything the export leaves out.
One detail worth knowing before you rely on it: wherever the export contains a URL — a login’s site, a merchant entry on an agent card, a webhook address — it gives you the host only. Any path, query string, fragment, or embedded credentials you saved are stripped, so the export will not always match the value you typed. Ask us if you need the exact stored strings.
It does not currently include your transaction history; your session audit trail and receipts; your notification history; your push-subscription records (the device endpoint and browser keys stored when you enable notifications); your approval, security-code, and challenge prompt records; your webhook delivery logs (destination URL, signed body, signature); the signing secret an agent card uses to sign your webhook calls, which the dashboard does show you; the billing identifiers Stripe issued for your account; or the subject identifier our authentication provider uses for you, which is the link between your sign-in and your Agent Vault account. Nor does it include the operational request logs described in §2 — IP addresses, user agents and timestamps — which our hosting and backend providers hold on our behalf rather than in your account record. If you want any of those, ask and we will provide them.
Complaints
If you are in the EEA, the UK, or Switzerland you may complain to your local data protection authority. We would appreciate the chance to address it first at [privacy@…].
12. Security measures
What follows is what our system actually does. We hold no security certification, and we do not claim one.
- Your secrets are never returned to the agent. It works with mock tokens; the substitution happens in a browser process your agent drives but cannot read out of — script evaluation is refused, and its screenshots are redacted. That is a narrower statement than “the agent never has them”, and deliberately so: the agent controls the session. The keyboard route out is closed, though — once a real value has been substituted, every clipboard-capable chord is refused (only Shift+Tab and Alt+Left/Right survive, which move focus and copy nothing), so a value it cannot read cannot be copied out with a shortcut either. §4 describes the path and the guard (issue #252).
- Card numbers are held in a PCI-DSS Level 1 vault (Basis Theory’s certification, not ours), tokenized directly from your browser. A card added today cannot land in our database — the write path takes a vault token id, never a number, though it does store the non-secret metadata in §2 alongside it. Encrypted numbers from the pre-vault design may still sit in legacy rows until the purge job clears them (§5).
- Security codes are not stored — they are entered by you per purchase and held only in the proxy’s memory, for that session, on the same redaction-driven terms as a card number (§5). As with card numbers, a legacy column is still being purged (§5).
- Credentials are encrypted at rest. Records written under the current scheme use a per-record key wrapped by a key-encryption key and are bound to your account, so they cannot be decrypted for someone else. Older records may have neither property until they are re-keyed (§6).
- Every fill is authorised server-side and fails closed. Every value — card, security code, password, one-time code, identity field, address — is released only to a live, non-revoked API key bound to your account, so revoking a key stops resolution immediately.
- One exception to that, worth knowing: a challenge handoff page that was already open when you revoke the key is not cancelled by the revocation — it is authorised by its own short-lived link rather than re-checked against the key, so completing the bank prompt on it can still land on the paused checkout until the link is used or expires, minutes at most. If you revoke a key to stop something in progress, do not then complete an outstanding handoff. Making revocation settle open prompts is tracked as issue #212.
- A security-code prompt is not an exception. Entering the code after you revoke the key does not get it to the checkout: the card is re-authorised once the code arrives and before it is released, so a revoked key, a paused card, or a changed merchant policy stops it there. We previously listed this alongside the handoff, which overstated how weak revocation is.
- The spending controls do not cover everything, and we would rather say so. An agent card’s merchant allowlist, pause, and approval threshold govern card and security-code fills. Its spending limits are narrower still: they bind card-number fills only, so a checkout asking for the security code alone is never counted against them (§4). Pausing an agent card does not stop that agent from resolving a saved password, a one-time code, an identity field, or an address — those are governed by key scope, account binding, and (for logins) the site lock, but not by pause. To stop everything at once, revoke the API key. Extending the pause control to the other secret types is tracked as issue #181.
- API keys are stored hashed and can be revoked instantly. Scoping is optional: you may restrict a key to chosen cards and logins, but a key created with the scope controls left on “All” has access to all of them. Identity fields and addresses are not per-key scopable at all — any live key on your account can resolve them. Scope your keys deliberately; the default is not the narrow one.
- The audit trail is built from token kinds, not values, and the storage boundary rejects card-shaped strings and unknown token kinds. It is not, however, structurally incapable of holding a secret: the host, field, reason and detail slots accept free text, so the guarantee rests on what our own service writes into them rather than on a rule the database enforces.
- No advertising or third-party tracking anywhere, and no analytics on our website. Our own aggregate telemetry about merchant-site breakage is described in §2 and carries no identifier for you.
- Traffic between you, our services, and our providers is encrypted in transit with TLS. Traffic to a site your agent visits is encrypted when that site is
https://— which is every real checkout — and a plainhttp://page is refused rather than filled, so a real value is never typed into a document that is not TLS-protected (§4).
What we are not claiming. The card number is currently revealed inside our proxy process during a fill (§5); the isolated, attested enclave described in our marketing FAQ is not deployed. The key-encryption key protecting your credentials is held by us. Our vault account is an evaluation tenant. This is a preview environment, and no method of storage or transmission is perfectly secure. Do not put data you cannot afford to lose into it.
13. Cookies and local storage
We set two kinds of cookie: one to sign you in, one to count visits. For signing in, our authentication provider sets an encrypted session cookie, and during sign-in and token refresh a short-lived workos-access-token cookie may also be set, which the app reads once and then immediately clears. Both are strictly necessary for the service to work. The second kind is the analytics cookie described in the next paragraph.
We set no advertising or cross-site tracking cookies, and nothing we set follows you to another website. Our product analytics does set one first-party cookie holding a random device identifier, so that two pageviews in the same visit are not counted as two visitors. It is not shared across sub-domains, it is not tied to a profile, and it is described in full below.
No third party sets a cookie through our site, with one exception you have to visit deliberately: our Stripe demonstration page (/stripe-demo) loads Stripe’s own script from js.stripe.com and mounts a card field that Stripe, not we, renders. Stripe sets its own cookies there for fraud and device recognition, governed by Stripe’s privacy policy rather than this one. The card details you type there go to Stripe, never to us; what comes back to the page is Stripe’s token metadata — a token id, the card brand and the last four digits — which the demo simply displays. We do not send it anywhere or store it: it lives in the page until you navigate away. No other page on this site loads that script, so if you never open the demo, no third-party cookie is ever set.
Your browser’s local storage holds up to five values. Three are display preferences with no personal content: your light/dark mode (av_mode), your visual style (av_aesthetic), and your accent colour (av_accent). If you used this site before those keys were renamed you may still be carrying their predecessors — sap_mode, sap_aesthetic and sap_accent. We read them so your theme survives the rename, but we never write them again, and clearing your site data removes them.
The fourth is the desktop-notification opt-in, and it does contain personal data: the key is sap.desktopNotifications.<your account id>, so your account identifier is written into your browser’s storage and stays there. It is scoped that way deliberately, so that on a shared browser a later sign-in does not inherit someone else’s opt-in. Turning the notification off removes the entry.
The fifth belongs to our product analytics (ph_…_posthog), and mirrors the cookie described above: a random device identifier and the state the SDK needs between pageviews. It is not your account id and it is not linked to one.
All five stay on your device except as described in the analytics paragraphs below — nothing else reads them back to us — and clearing your browser’s site data removes all of them. Your API keys are deliberately never written to browser storage of any kind.
What the analytics actually collects. Pageviews and a small number of product events. It is configured against its own defaults, deliberately: no session recording, no autocapture of clicks or form fields, no heatmaps, no scroll or performance properties, no error capture, no surveys or experiments, and no feature flags. URLs are reduced to a route template before they are sent, so a path carrying an identifier is reported as its shape rather than its contents, and query strings and fragments are dropped. It creates no person profile and we never associate the device identifier with your account. On the token-gated pages — the ones you reach through a token-bearing link, including the live card-code page — it never starts at all.
Because we load web fonts from Google Fonts, Google receives your IP address and user agent whenever a page loads. See §8.
14. Children
Agent Vault is not directed at children and is not for anyone under 18. We do not knowingly collect personal data from children. If you believe a child has given us personal data, contact [privacy@…] and we will delete it.
15. Changes to this policy
We will update this page as the product changes — in particular as the gaps flagged in §5 and §10 are closed. When we make a material change we will update the effective date at the top and, for changes that affect how we handle data you have already given us, notify account holders by email before the change takes effect.
This document is a draft pending legal review and is not yet in force.
16. Contact
Privacy and data protection: [privacy@…]
General support: [support@…]
Postal: [LEGAL ENTITY NAME], [REGISTERED ADDRESS]
See also the Terms of Service.