Your phone number is never stored
When you call, the number you dialed from arrives at our server for about 400 milliseconds — long enough to route the call and check your rate limit. It is never written to a database, never logged to disk, never sent to a third party. After that 400ms window, it exists only in the one-way hash described below.
We don't log inbound numbers at the carrier handoff. We don't pass them to analytics. There is no audit trail with your number in it anywhere in our system. This is not a data retention policy. It is a data non-collection policy. You cannot retain what you never write down.
How the one-way hash works
We run your E.164-formatted number (e.g. +12125551212) through bcrypt with a cost factor of 12. bcrypt is a one-way function: given the hash, you cannot recover the original input. This is the same technique used to store passwords everywhere that takes security seriously. The output is a fixed-length string that looks like $2b$12$9KnR... — it bears no resemblance to a phone number and reveals nothing about the number that produced it.
The "one-way" part is load-bearing. It is not encryption. Encryption can be reversed with a key. A bcrypt hash cannot be reversed at all — not by us, not by anyone who gains access to our database, not by a court order. The math doesn't permit it.
The pepper problem (and why it matters)
bcrypt alone isn't enough. A determined adversary with our database could run every phone number in the world through bcrypt and compare the resulting hashes against ours — there are only about 10 billion possible North American numbers, which is feasible to brute-force given enough time and hardware. So we add a pepper: a secret string that gets mixed into the hash input before bcrypt runs.
The pepper is stored in a separate secrets manager, completely isolated from the database. Without the pepper, the hashes in our database cannot be cracked even if someone steals the entire database — an attacker would need to compromise both systems independently, which have separate access controls, separate audit logs, and separate breach blast radii. The pepper also means that rotating it (changing to a new secret string) invalidates every hash in our system, which we treat as an emergency option if we believe a compromise has occurred.
What the database actually contains
For each call: a bcrypt+pepper hash of the caller's number, a timestamp, a message ID, and the processing status. That is it. There is no name, no carrier, no location, no device fingerprint, no IP address. The hash is used for exactly one purpose: enforcing our rate limit of 3 messages per number per 24-hour period. It is not used for tracking, for analytics, for pattern analysis, or for anything else.
If you subpoena our database, what you get is a list of opaque hashes, timestamps, and message IDs. The timestamps tell you when calls happened. The hashes tell you nothing. You cannot work backwards from a hash to learn whose call it was.
What happens if we get a subpoena
We will comply with valid legal process. What we can produce: the message audio, the transcript, the timestamp, the message ID, and the bcrypt+pepper hash of the caller's number. What we cannot produce: the caller's identity, their phone number, their location, or any other identifying information. We genuinely do not have it. A court order cannot compel us to produce something we don't possess.
This distinction matters. "We have it but won't give it to you" is a policy stance that can be litigated, pressured, or overridden. "We don't have it" is a technical fact. We have engineered our way into the second position deliberately. For more detail on legal process and our response procedures, see the legal page.
We do not have the ability to identify a caller — not for advertisers, not for governments, not for ourselves. This is an architectural guarantee, not a policy promise.
Retraction codes
The 6-digit retraction code you hear at the end of your call maps to your message ID, not to your phone number. To retract a message, you enter the code on our retraction page — no login, no identity check, no number verification. The code is the credential, and the code has no connection to who you are.
This also means: if you lose the code, we cannot look it up for you. There is no "forgot my code" flow because any such flow would require us to tie your identity to your message, which we refuse to do. The code is the only link between you and the message. Write it down. We will not be able to help you if you don't have it.
What we genuinely can't protect against
Voice masking changes your pitch and formants, but your cadence, accent, and speech patterns can still identify you to people who know you well. We can anonymize your number. We cannot anonymize your voice completely, and we will not pretend otherwise.
If you call from a phone with caller ID enabled, your carrier logs that you dialed a toll-free number. We don't see this data — it lives at your carrier, not with us — but it exists. If you need to protect yourself from a threat model that includes your own carrier, call from a payphone or a number that isn't linked to your identity.
If you're in a jurisdiction with aggressive telecom surveillance infrastructure — countries where the state monitors call metadata in bulk — calling any number from a personal phone carries inherent risk, regardless of what the service on the other end does. Know your threat model. We can protect you from us. We cannot protect you from your government or your carrier.
If you have specific questions about our technical architecture that aren't answered here, write to hello@psa.xyz. We will respond to good-faith technical inquiries.