//privacy
Privacy Policy
This page is an inventory: what our servers actually hold, what they cannot read, what leaves your phone and to whom, and the places where the design falls short of what “private” might make you assume. Every claim is written to be specific enough to hold us to, and to check against the source — which is not published yet, and which section 17 tells you how to get today.
Effective 25 July 2026·Last updated 29 August 2026·Covers the Tacendum iPhone app, tacendum.com, and the command-line client and MCP server
The short version
- Your messages and calls are end-to-end encrypted. We cannot read them and hold no key that would open them — section 03.
- We do not know who you are. An account is a keypair your phone generates; we hold a random id and no name. If you choose to link an email address or a username so that people who already know it can find you, we hold a keyed scrambling of it — never the thing itself — section 02.
- We know which account messages which account, and when. There is no sealed sender: every message writes a row naming sender, recipient and time — section 04.
- A room — up to twelve people — hides what is said in it, not who is in it. We see who each copy goes to, so an operator who wants the member list can infer it — section 05.
- Your conversations live on your phone, not on ours. We keep no archive, and a lost phone is a lost account, with no recovery — section 02.
- An iPhone backup should not carry your Tacendum messages or your keys. A few small shared files are still backup-eligible — section 08 says what is and is not in a backup, including the honest caveats on the word “excluded”.
- If you take a screenshot inside a conversation, the app tells the other person — everyone in it, if it is a room. No setting turns it off; one narrow exception is named in section 08.
- When your phone is offline, the encrypted message goes to Apple to be delivered. Apple cannot read the body; Apple can see the pattern — section 07.
- Nearly every call touches our relay host, and a call to someone new is relayed by default. The host sees your phone’s public address on essentially every call and can hear nothing — section 06.
- If you report someone, only the messages you explicitly attach become readable to us. The default report contains no message text at all — section 04.
- No analytics, no trackers, no advertising, no crash reporter, no contact upload — section 09. The app talks to five destinations, all of them ours: our API, the live message connection, the storage host it uploads attachments to, the delivery network it downloads them from, and our call relay.
- Reading this website sets no cookies and loads nothing from anywhere else. Two qualifications — the waitlist spam check and the firewall’s request sample — in section 12.
If you need a system where the operator cannot learn which account talks to which, Tacendum is not that system today. Sealed sender is not implemented. Encryption hides what you said; it does not hide that you said it, to whom, or when. That is a real limit, and it is near the top of this page for a reason.
What an account is
An account is a cryptographic keypair. Registering is one tap: your phone generates a long-term identity keypair, asks us for a random challenge, signs it on the device, and sends us the public half of the key, the challenge and the signature. We check the signature and hand back an account id — a random, time-ordered string of 26 characters — and a session token. No phone number, no code, no email address, no username, no name: none is asked for and none is needed. Any of them you link later is optional and revocable, and the rest of this section says exactly what we hold when you do.
The private key never leaves the device. It is never uploaded, and the only thing that comes back from the signing call is the signature itself. On the phone it is a file in the container the app shares with its own notification extension — the extension has to decrypt a message that arrives while the app is closed, so it needs the same store — not in the iOS Keychain. That container dies with the app: deleting the app destroys it and the key with it.
Your account row holds: the account id, the time it was created, a registration id, your public identity key, a signed prekey and a post-quantum (Kyber) prekey. Every one of those is a public half, stored in plain text. There is nothing else on the row, except — for the small number of integration accounts described below — a marker saying so and the id of the account that owns it.
A second row claims your identity key, so that exactly one account can hold it. That row is keyed by the public key itself, in the clear. As long as your phone still holds the private key, signing in again returns the same account; if the key is gone, that row is what stops anybody else ever taking the account over — nothing more. It does not survive deleting the app, because the key does not.
The key cannot be changed, and that has consequences
An account is bound to one identity key for as long as it exists. If a device presents a different key for an existing account, our server refuses the upload with a conflict error whose text is “this account is bound to a different identity key; a new key is a new account”. There is no rotation and no rebinding.
So if you lose the private key — a lost phone, a wiped phone, the app deleted and installed again, a restore onto new hardware:
- You cannot get that account back, and neither can we. Signing in means signing a challenge with the private key, and we hold no fallback.
- Deleting it needs the same key. Deletion is an authenticated request, so a lost key means the app cannot delete the account either. We can remove rows by hand (section 18 is the one case where we commit to it), but we will not delete an account because somebody quotes its id at us: an account id is a public thing, and acting on a bare id would be a way of taking an account away from its owner. So a stranded account row and its identity-key claim stay on our servers, because nothing expires them.
- Starting again gives you a different account with a different id. A fresh keypair produces a fresh account, not the old one restored.
- Nobody you know is told. Your old id simply stops working; messages written to it sit as sent until they expire after thirty days. You hand people the new 26-character id yourself.
A changed safety number has no innocent explanation here. A safety-number warning fires only when the same account id presents a different key, and our servers make that impossible — a new key mints a new account with a new id, so reinstalling, restoring a backup or moving to a new phone produces a new contact, never a changed number. The app says exactly this when it happens, and tells you to treat it as somebody trying to read the conversation until you have checked in person or on a call you placed yourself.
We cannot look you up
The accounts table has no secondary index, deliberately, and no code we run on the internet holds permission to query or scan it — only to read one row at a time by a key the caller already supplied. So there is no directory, no browsing, no bulk “is this key registered” oracle, and no feature of this product that can produce a list of our users. What does exist since 29 August 2026 is one narrow lookup: type an exact email address or username into the app and, if its owner linked it and switched findability on, the lookup answers with that account. Every other answer — not linked, linked but not findable, or nobody there — is the same bytes in the same time, so the lookup cannot be used to learn who is on Tacendum. Searching needs a verified email on the searcher’s own account, an account at least three days old, and is allowed a limited number of times a day, under a daily ceiling for the whole service with an alarm on it. The precise limit: it is still our own database, and an operator holding administrative credentials could read rows out by hand; what does not exist is any running service that lists anyone. You add someone by scanning their code in person or receiving it another way; the code is a bare account id with no scheme, no prefix and no URL, so scanning it causes no request to any server at all.
Integration accounts
A separate class of account exists for automation, marked on the row and bound to an owning account. Our servers enforce who those accounts may send to and who may send to them, so the recipient of a message is checked on our side. When an integration account is retired — revoked by its owner, or deleting itself — its identity key is tombstoned: the claim row stays permanently so the key can never be registered again. The tombstone survives account deletion, and no code anywhere clears one.
There is residue from the old design. Tacendum used to register accounts by SMS. That path is gone — no code left can send an SMS, and no permission anywhere in our infrastructure to publish one — but the rows it wrote are still in the accounts table, keyed by phone number in international format, and account rows written before the change may carry a number as a leftover field. No code path deletes them. Write to hello@tacendum.com and we will remove yours by hand — without a verification ritual, because the row is keyed by the number itself and there is no account behind it to steal.
What encryption covers, and what it does not
Your phone encrypts a message before it leaves the device, using the Signal protocol with a post-quantum key exchange. Our servers hold only public keys, and no code on our side decrypts anything — there is no decryption call anywhere in the server. So the following are not things we promise not to look at; they are things we are not able to look at:
- the text of every message
- photos and files you send, and the keys that would decrypt them
- your display name, your “about” text and your avatar — these are not fields on our servers; the profile card travels inside the same encrypted envelope as a message
- reactions, replies, edits, retractions and screenshot notices
- the disappearing-message timer for a conversation, which is agreed inside the same encrypted envelope — between the two phones in a one-to-one conversation, and between every member’s phone in a room
- a location you choose to share — bare coordinates inside the envelope
- anything you keep in the shared vault
- call set-up and call media — the audio and video are encrypted between the phones on the call, pairwise, exactly as messages are
The wire format for a message body accepts base64 text and nothing else. Our servers store that string and hand it back to the recipient without ever decoding it. There is no server-side schema for a reaction or a name, because those never arrive as fields — only as ciphertext.
Our servers do perform cryptography, just never on your content. They read a public key and check a signature at sign-in; they store a SHA-256 digest of a session token instead of the token; they compute a plain unsalted SHA-256 hash of your account id for the activity counter — section 04 says what that does and does not protect — and a keyed hash for relay credentials; they sign a short-lived token to talk to Apple’s push service; and they sign attachment download links. None of it touches a message.
What encryption does not cover
These are visible to us:
- Which account sent, which receives, and when. Stored in the clear on every queued message, to the millisecond, with a message id. Size is not a stored field, but the ciphertext sits on the same row, so its length is there to be measured.
- Whether a message opens a new conversation. Each queued row carries a flag saying whether it starts a fresh cryptographic session — relationship-formation metadata: we can see when two accounts begin corresponding.
- Both ends of every send, in real time. We read the sender’s row to enforce the integration rules and the recipient’s row to reject an unknown recipient, and every accepted message is queued before we look for a live connection — so the pair is on our servers for every message, one such pair per member for a room (section 05).
- That a frame is a carrier rather than conversation. Read receipts, reactions, edits, deletions and profile syncs carry a “do not raise a notification” bit. The server cannot tell which it is — but a small transport-labelled frame moments after someone wrote to you makes a read receipt inferable. Screenshot notices are deliberately not in that set: they are sent as conversation and raise a banner, because they are news rather than bookkeeping.
- That a frame is probably a call invite or a hangup. Call offers and endings carry an “urgent” bit; without it a call could never ring a locked phone.
- That you fetched someone’s keys. The rate-limit counter on a prekey-bundle request is keyed by both account ids — a directed edge in a contact graph, in a database, for the counting window plus one hour. A message that wakes a sleeping phone takes a counter keyed the same way (section 04).
- Coarse online status of the person you message. We tell your app delivered if their device had a live connection at that instant, or sent if it did not.
If someone compelled us, or broke in while a message was waiting, they would learn that one account sent something to another account at a particular second, roughly how large it was, and whether it was the first thing those two had ever exchanged. They would not learn a word of what it said. That pattern — who, whom, when — is the social graph, and we can see it.
What the app sends us
The app makes nineteen kinds of request to our API, plus one live connection for messages. Everything below is the whole of what those requests leave behind.
Signing in
Signing in is two calls. The first asks for a challenge; we store it keyed by your public identity key for 120 seconds or until it is spent. The second returns your signature; we check it and issue a session token.
We store only the SHA-256 digest of that token — never the token — so a copy of our database yields no usable logins. The record holds the digest, your account id and two timestamps, and expires after thirty days. Signing in again supersedes every earlier session, and sessions can be ended individually or all at once from the server side.
The live connection uses a single-use ticket minted over HTTPS, not the thirty-day token. The ticket is stored as its own value — not a digest — for up to sixty seconds and destroyed on first use. It is the one credential we hold in recoverable form.
Public key material
Your app uploads a registration id, an identity public key, a signed prekey, a post-quantum (Kyber) prekey, and a pool of up to a thousand single-use prekeys — all public halves. Each single-use prekey is handed to exactly one person starting a conversation with you, and deleted as it goes. Re-uploading destroys and replaces the whole pool — never the identity key, which is fixed for the life of the account.
Message envelopes — the part encryption does not hide
Every message you send to one person creates a row in our delivery queue; a message to a room creates one such row per member (section 05). The row holds the recipient’s account id, a message id, your account id, whether the message opens a new session, a server timestamp, and the encrypted payload. It is deleted only when the recipient’s device acknowledges receipt; if their phone never comes back, it expires after thirty days undelivered.
The payload is opaque to us, and stays opaque. The envelope is not.
Photos, files and other attachments
An attachment is encrypted on your phone with AES-256-GCM under a fresh random key, and only then uploaded — to storage under a 256-bit random identifier, capped at 10 MiB. The key that would decrypt it travels inside the encrypted message and never reaches us. We store no record linking a blob to a sender or a recipient: possession of the random identifier is the only thing that can fetch it, and the upload and download links we mint are valid for ten minutes and used by your phone directly — the file never travels through our API. Uploads go straight to the storage service; downloads come through our own delivery network — a distinction that matters in the paragraph below.
Storage-level access logging is switched on for the attachments bucket: each record names the requesting address, the time and the object identifier. Downloads come through our content delivery network, so the log shows the network, not the recipient’s phone — and request logging on the delivery network itself is deliberately off, so recipients’ addresses are not retained. Uploads go straight to storage, so the log shows the uploading phone’s address next to the object identifier — the most identifying thing we hold.
It exists because object-level access records are how a theft from that bucket would be reconstructed, and nothing else in the system would show it. The log expires after thirty days — matched to the attachment it describes, so the record of who fetched a blob dies with the blob rather than outliving it. It was configured at ninety days on 4 August 2026, ahead of the 31 December 2026 commitment this page previously carried, and shortened to thirty on 14 August (section 20). Nothing there is exported, joined to any other table, or read except in response to a suspected incident.
Being online
While your app holds a live connection we keep one row — your account id, a connection identifier, the time you connected — so an incoming message can be routed to your phone. It is deleted on disconnect, on account deletion, and when a delivery to a dead socket fails. The table has no expiry, so a row orphaned by a disconnect we never observed sits there until one of those happens: for those accounts we are holding something close to a last-connected time.
Linking an identifier
A linked identifier — only if you link one. If you link an email address, or claim a username, we hold one row: a keyed scrambling of the identifier (a secret we keep, applied to the normalised form), the time you verified it, and your findability switch, which is off until you turn it on and separate for each identifier. The address itself passes through our server when you type it and each time a code is sent, and is not stored. Be honest about what the scrambling buys. An email address is hard to guess, so a leak of our rows alone does not reveal it. A username is public by nature — an email address is private information; a username is not. We store only a scrambled form of your username, never the name itself, so a leak of our records alone does not reveal it; usernames are short and guessable, so the real protections are limits, not scrambling: every search and every claim attempt is strictly limited and monitored, no one using the app can find your account by name unless you allow it, and you can change or remove your name at any time. Treat your username as public information. Removing an identifier deletes its row; a username you give up is held back from anyone else for thirty days, then freed; deleting the account deletes every identifier row of yours, apart from that thirty-day hold on a username.
Consenting to an AI agent
Integration accounts (section 02) are how an AI agent reaches you, and since 15 August 2026 an agent that is not your own may only reach you if you have said so. Saying so writes a row: your account id and that agent’s account id, and nothing else — no room, no reason, no time of your choosing, no message. Our servers read it as a yes-or-no on the two ids they already have in front of them, one pair at a time, before letting a frame through.
Two properties are worth stating precisely, because they are the difference between a permission and a profile.
- Nothing can list it. The table has no secondary index and there is no request in our API that reads one back — not for you, not for the agent, not for the person who operates the agent. The only way to reach a row is to already name both ids, which means neither we nor anyone else can ask “who has this agent been given permission by”. The one exception is deletion, which sweeps your own side of it.
- It does not expire. Everything else described in this section reaps itself on a clock. A consent record is a standing permission, so it lives until you withdraw it — in the app, or by deleting your account — and until then we hold it. Withdrawing the last one leaves the table holding nothing about you at all, including the counter that tracks how many you have.
Being honest about what that is: it is a record of a decision you made about another party, held by us, with no expiry. It sits in the same class as the pair counters below — but those are traffic, and this is a choice. What it is not is a contact list: it names account ids you already handed out, there is nothing to walk, and an agent’s operator can learn a member’s answer only by sending to that member and seeing what happens, which section 05 makes visible in the room anyway. The one thing withdrawal does not undo is described in section 11: messages already queued before you withdrew keep draining.
How many people used it
We count how many accounts were active in a day, and to do that we write one row per account per hour: a SHA-256 hash of your account id, the day, the hour, and an expiry thirty-five days out. No message, no recipient, no address — the fact that someone acted, and when, to the hour.
That hash is unsalted, and calling it a hash is doing less work than it sounds like. It keeps raw account ids out of this one table, which matters if this table alone were ever exposed. It is not protection from us: we hold every account id already, and can compute the same digests and read this table as though it named you. A salt would change that, and we have not implemented one.
IP addresses
Not one place, and not two. Here is the whole list we can find.
- The attachment upload log described above. An address next to an object identifier, kept thirty days.
- The counter that throttles the unauthenticated sign-in endpoints, keyed by the raw source address — a database row, not memory, living its counting window plus one hour.
- Our call relay host, which observes your phone’s public address on any call that gathers network candidates and writes a session log on its own machine. Section 06.
- Our infrastructure provider’s firewall on this website, which keeps a rolling sample of requests — ordinary page reads included — with source addresses, for a few hours. Section 12.
- Our infrastructure provider itself, which unavoidably sees the address of every request where it terminates TLS, whether or not anything records it.
What is genuinely negative: no IP address is written to any application log line, and the gateway access-log format is defined so that the client address is not one of the fields it can record. Our databases have continuous backups switched on, so a rate-limit row holding an address can remain restorable for longer than its own expiry — see section 10.
Rate-limit counters
These are short-lived numbers, but the key is the disclosure. Each row holds a bucket name, a count and an expiry, and lives its counting window plus one hour — about an hour for most, about two for the three whose window is itself an hour (relay-credential mints, push-token writes, abuse reports). The whole set as of this revision:
- keyed by source IP address: sign-in attempts.
- keyed by your account id: sending on the live connection; sending as an integration account; minting a live-connection ticket; minting relay credentials; registering or removing a push token; deleting an account; filing an abuse report; binding an integration; adopting a machine into a crew; minting an upload link; requesting a download link — a per-minute counter that deliberately keeps the attachment identifier out of the key and out of the log, so it shows that the account fetched something but never which stored file; revoking sessions; and two separate counters for the pushes your messages and your calls cause.
- keyed by the receiving account’s id: the ceiling on how many message notifications one phone may be sent in a minute, which exists so that several accounts each staying inside their own budget cannot together flood one phone. It suppresses a banner, never a delivery.
- keyed by both account ids: fetching someone’s keys, and each sender’s share of that notification ceiling — so a message that wakes somebody’s phone writes a row naming you and them. In a room that is one such row per member whose phone was asleep (section 05).
Logs
Our application log is a stream of single-line JSON records: a timestamp, a level, an event name, and simple scalar fields. Ten events carry an account id, and that list is complete: an account was created (with its class), a sign-in succeeded, prior sessions were revoked, a prior-session revoke failed, a session was revoked, other sessions were revoked (with a count), an account was deleted, a key upload was rejected as immutable, an integration was bound, and an integration was revoked.
Around thirty other event names exist and none carries an account id — a challenge issued, a signature rejected, a connection authenticated with a named scheme, a push token registered, pruned or deleted, a push completed or failed, Apple’s refusal with status and reason, relay credentials minted with a lifetime and server count, an upload link minted with a content length, and so on. The account-id list above is the one we have checked line by line.
Message payloads, message ids, attachment ids, device tokens, session tokens, connection tickets and identity public keys are all deliberately kept out. Gateway access logs carry a request id, the route and a status — plus a response size (HTTP) or connect/message/disconnect (WebSocket) — and never an address, an account id, a query string or a body, which is why the connection ticket never appears in one.
These logs are kept for ninety days, and they survive the infrastructure being torn down.
Two honest qualifications, because “our logs contain only the list above” would be a stronger claim than the code supports.
First, keeping secrets out of the log is a rule enforced by review, not by the type system — the logger’s own source says so. Three error paths record the raw text of an exception, and whatever a cloud SDK puts in that text is kept ninety days. One line records the identifier — not the value — of a secret that cannot be used. And one background function has no catch-all, so a failure there is written by the runtime itself as an error object and stack trace.
There used to be a fourth, and it was the worst of them: a deployment probe on the sign-in service that returned raw error text to whoever called it, with no authentication and no per-address counter. It has been removed from the software along with its route; the removal reaches the running service with the next deployment of the sign-in service.
Second, the logs are read by machine: a filter counts account-creation events and feeds an alarm that fires at sixty accounts minted in an hour. The count carries no account id, and it outlives the ninety-day log retention as a metric.
Reporting someone — the one thing you can choose to show us
Everything described above is ciphertext or an identifier. There is exactly one exception, and it only ever happens because you decide it should: if you report someone, you can attach messages, and attached messages are readable by us.
Reporting exists because an app that carries messages between people has to offer a way to raise one — Apple requires it. We cannot scan conversations to find abuse; that is what the encryption means. What is left is asking you.
The default report contains no message text at all. It is the account you are reporting, a category, and the fact that you sent it. That is a complete report, and it is what the app sends unless you go further.
If you do choose to attach messages, this is exactly what happens and what does not:
- Only what you pick. Nothing is gathered for you, and there is no button that attaches a recent conversation. You choose messages one at a time, and the screen tells you before you send that the text will be readable by us.
- At most five, and each is capped in length. The limit is deliberate: it keeps “report” from quietly becoming “upload this conversation”.
- No message identifiers travel, and no ciphertext. Your phone also rounds each message’s time down to the hour before sending. Both are so that a report cannot be lined up against the delivery records we already hold — the joining-up we spend the rest of this page avoiding.
- We store the report for a hundred and eighty days, then it is deleted. Longer than our other records, because a pattern across months is the thing that identifies a repeat offender; still an expiry, not indefinite.
Two things about the other side of it. We do not tell the person they were reported, and nothing about it appears in your conversation with them. And the systems that write a report cannot read one back — a permission boundary, so the path a stranger might reach cannot be used to find out who reported whom. Reports are read by a person, with credentials no part of the service holds.
Reporting is not blocking. Blocking is immediate, needs nobody’s agreement, and is the stronger move; reporting asks us to look. The app says so at the point you use it.
Rooms
A room is one conversation for up to twelve people, counting the person who made it. The encryption is the same encryption. What changes is the shape of what we hold, and that is the half a reasonable person would guess wrong.
A room message is not one message
There is no room on our servers: no room record, no roster, no room name, no member table and no room id — not in the clear, not encrypted, not hashed. A room exists on the phones that are in it; each phone works out who is in it by folding together the membership changes it has received, each of which arrived inside its author’s own encrypted session. Nothing about that computation reaches us or needs us.
When you send to a room of eight, your phone encrypts the message seven times over — once per other member, under the same one-to-one Signal session it would use to write to that person alone — and sends seven separate messages, each addressed like an ordinary message. The room’s id, name, roster and agreement digest all travel inside the ciphertext; nothing on the outside joins the seven to each other — no room id, no shared identifier, no sequence number, and the message ids are freshly random rather than time-ordered, because seven ids minted in order under one sender would be a free and durable way of joining them back together in our queue.
So what we hold for one room message is N rows, not one — each exactly the row section 04 describes for one person: your account id, one member’s account id, a message id, the new-session flag, a server timestamp, and the ciphertext whose length is there to be measured. The frame bits in section 03 apply per leg; the urgent bit appears on a room’s legs only for its voice call’s signalling.
The multiplication reaches Apple as well: each leg whose recipient is not connected goes to Apple’s push service on its own, so one message to a room can put up to one push per member through Apple, within a few seconds. Section 07 sets out what each push contains.
The room is hidden from us as data. The sending is not. Its name, its membership and every word said in it are things we cannot read, because they are not fields — they are ciphertext. But we see who each copy goes to. Seven envelopes leave your account for seven particular accounts within a few seconds, and then again on the next message, and the next. A server operator who wants the member list gets it. That sentence is the app’s own, quoted exactly — it is what you are shown before you make a room, and it is not softened here: a room does not hide its membership from us. It hides its contents. If what you need is that we cannot work out who is in a room together, this design does not give you that, and no amount of encryption in it ever will.
One qualification in each direction. The legs are paced and shuffled rather than sent as one burst, so the inference costs work rather than being handed over — that raises the price; it does not change the answer. And the most durable trace is not a message at all: for each member whose phone was asleep, the push also takes a rate-limit counter keyed by both account ids, yours and theirs (section 04), which can outlive the queued message that caused it.
What does not happen is accumulation. There is no room table, no job that assembles a roster, and nothing that joins those rows into a history — a pattern passes through our hands rather than becoming a record we keep. Section 19 draws the same distinction for legal demands.
Who can do what, and where that is decided
None of the rules below run on our servers. Every phone folds the same authenticated writes into the same answer about who is in the room and who runs it; we carry envelopes we cannot open and enforce nothing. Rooms changed exactly one number on our side: the ceiling on message notifications one phone may be sent in a minute rose from ten to twelve, because a member of a full room can legitimately be woken by eleven other people. It records nothing.
- Twelve people, the person who made the room included. The cap is not a tier and there is no larger room to buy: a room message costs one delivery per member.
- Only the person who made it can add or remove anyone. Anyone can leave whenever they like, and nobody — not even the owner — can put back someone who left: being added again arrives as an invitation, which that person accepts or does not.
- Somebody added later sees nothing that was said before. Each phone encrypts to the roster as it stands at the moment of sending, so no earlier copy exists that a newcomer could open. The owner can deliberately send a newcomer a stated number of recent messages, and when they do the room is told, in the room, that it happened and how much. Anything the disappearing timer has taken is gone and is not sent.
- Deleting a room deletes it from your phone. Nobody is told, and it comes back with the room’s next traffic if you are still a member. The person who made it can delete the room for everyone — reaching the phones that come back within the thirty days a queued message lives, and never what anybody has already saved.
- Rooms send no read receipts at all, whatever your read-receipt setting says.
- A room containing somebody you have blocked is read-only for you — your phone will not quietly send around them. Section 08 says what a block cannot do in a room you share.
Safety numbers in a room
A safety number is between two people, so a room does not have one — you compare numbers person by person, in each person’s own conversation.
When a member’s safety number has changed and you have not yet reviewed it, your phone does not send them their copy, and the room says so by name. The other legs send and the room carries on — pausing a whole room for one member’s changed key would hand any member a mute button over everyone else, so only a one-to-one conversation stops entirely on that finding. The messages they missed are not sent afterwards when you accept the change, and the skip is something your phone and the room know, not something we do: what our servers see is one fewer copy.
A room can ring now, and only with voice
A room can carry a voice call of up to six people, counting you; video calls remain one to one, and a room offers no video call at all. (This page once said a room cannot ring — corrected when small-group calls shipped; section 20.) The call is built the way the room’s messages are — a separate end-to-end encrypted connection between each pair of phones on it — and its invites travel as ordinary encrypted envelopes, one per invited member, carrying the urgent bit that wakes a locked phone. So one incoming room call can put up to one call push per invited member through Apple. Section 06 is the whole of what a call involves, rooms included.
Calls
Tacendum has one-to-one voice and video calls, and a room can carry a voice call of up to six people — voice only; there is no group video (section 05). Audio and video are encrypted between the phones on the call, pairwise, so each leg’s keys live on the two devices at its ends and nowhere else. Call set-up — offer, answer, network candidates — rides inside the same encrypted envelope as a message, so what we see is a ciphertext row with the same from, to and time as any other, plus the “urgent” bit described in section 03 — one such row per invited member, for a room’s call.
The relay, and your IP address
A call needs the two phones to find a path to each other. We run one machine for that — a pinned build of coturn on a single instance at turn.tacendum.com — our own infrastructure, not a third-party relay vendor.
That one machine does both jobs. Address discovery and relaying are the same host on the same port. Before a call can be placed, your phone asks turn.tacendum.com what its public address looks like from the outside — that is what address discovery is — and the answer comes back because the machine saw the packet arrive. So our relay host observes your phone’s public address on essentially every call, including the ones that never go through it. The one narrow exception: if no relay is configured at all, our API says so and the app places a direct call with no relay in the path. (An earlier version of this page said otherwise — corrected by 5 August 2026; section 20.)
A call to someone for the first time is relayed by default — a direct connection reveals a home IP address to the other end, and the first call is exactly the one where that would be new information. After it, the app remembers what was chosen for that person, and a single app-wide switch forces relaying everywhere, overriding any per-person memory.
A room call takes the strongest answer on it. A call has one network path setting, so if any participant would be relayed, the whole call is relayed, including the legs to people you have called before. It errs toward relaying: the cost lands on us and on call quality rather than on your address.
So, precisely:
- On a direct call, the other person’s device learns your address, and so does our relay host. What our host does not do is carry the media or record an allocation for it.
- On a relayed call, the other person’s device does not learn your address, and our relay sees both. It cannot hear anything — it forwards encrypted media it has no key for.
- On a room’s voice call, the same holds leg by leg: our relay host sees every participating phone’s address, and each pair of phones on the call either connects directly — learning each other’s addresses — or through the relay.
What the relay records, and who could join it
The relay writes a session log to a file on its own machine. It rotates daily and is kept seven days, and it is never shipped to our central logging. coturn’s verbose mode — the one that writes peer addresses for every allocation — is deliberately switched off, and so are network flow logs on that machine. We have not audited every line coturn writes in the quieter mode it does run in, so: treat that file as capable of containing client addresses, kept seven days, on that machine only.
Credentials for the relay last twelve hours, are limited to five mints an hour, and are not stored in any database. The username inside one does not contain your account id: it is a truncated keyed hash of it under a salt the relay itself is deliberately not permitted to read. So the relay cannot join its own records back to an account, and neither can anyone who obtains those records without our salt. We hold the salt — correlation is something only the operator can do, rather than something nobody can do — so a demand or a compromise that reached both the relay log and our secret store could join the two. The event logged when a credential is minted records a count and a lifetime — no account id, no username, no credential.
Who can make your phone ring
“Silence unknown callers” is on by default. A call from someone you have never exchanged a message with produces a visible missed-call row instead of a ring. A blocked person never rings, whatever the setting says.
What a finished call reports to us
This page said until 19 August 2026 that no call statistics leave your device. That stopped being true on 13 August, and the correction is in section 20. Here is what actually happens now.
When a call ends, the app sends us one short report about it. It carries: whether it was audio or video, one-to-one or a room call, whether it was answered, whether it connected, how it ended — completed, declined, busy, unanswered, blocked, or one of three technical failures — how many milliseconds passed before it connected, how many seconds it lasted, and for a room call the largest number of people on it at once. It is queued on your phone and sent when there is a connection, so it goes up shortly after the call rather than during it. There is no setting that turns this off.
What it does not carry, and this is the part that decides how much it says about you: no account id of the person you called, no room, no message, no address, no device details, no network path, and nothing about who you are calling or how often you call them. The request is authenticated, so we know a report came from your account at that moment; the figures themselves are added into counters and a set-up-time measurement labelled only by direct or room, audio or video, and how it ended, with no account attached to any of them. Alongside that we keep one small row for eight days so that a report resent after a failure is not counted twice: it holds a hash of your account id combined with the report’s own random identifier, and a hash of the report’s contents. Neither hash can be looked up from an account id alone.
Why we take it at all: without it we cannot tell whether calling is working. A pile of connection failed outcomes is the only signal we would get that the relay is broken for somebody, and the encryption means there is nothing else to look at. That is a reason, not a justification you have to accept — section 11 says what deleting your account does and does not reach here.
What still never leaves your device. While a call is connected the app reads a single quality integer, computed on the device from packet loss and jitter, to draw the bars on screen. The native module also exposes a small statistics summary — already reduced on the device because a full WebRTC report would contain candidate addresses — which nothing in the app currently calls. None of that is transmitted, to us or to the other side: no bitrates, no packet loss, no jitter, no candidate addresses, no network diagnostics. And your call history — who you called and when — is written on your phone only.
Notifications, and what Apple receives
If you allow notifications, the app registers two tokens with Apple and sends both to us: a VoIP token, so a call can ring a locked phone, and an alert token, for messages. We store them in a row holding your account id, the two tokens, their Apple environment, the app’s bundle id and the time last updated — all in plain text, expiring ninety days after the last refresh.
Declining notifications does not switch Apple off entirely. Declining means no alert token, so no message ever produces a push. But VoIP registration is a separate mechanism, not gated by iOS on the notification prompt, and the app performs it before the prompt is shown. So a VoIP token exists whether or not you agreed to notifications, and an incoming call goes to Apple’s push service carrying that token and the calling account’s id; a row with no VoIP token never rings early.
There is a switch for this — Settings → Notifications → “Let Apple wake this iPhone” — added 4 August 2026 (section 20). Turning it off deletes the token row from our servers and stops this iPhone uploading another one; the setting is remembered across launches. What it costs is real and the app says so beside the switch: calls reach you only while Tacendum is open, and messages arrive with no notification. Deleting your account also removes the row.
What Apple gets
When a message arrives for a phone that is not connected, we hand Apple’s push service: the recipient’s device token, the sending account’s id — twice, once as the sender field and once as the notification’s thread id — the message id, the message type, a timestamp, and the encrypted message body itself. The visible text of the notification as Apple sees it is the word “Tacendum” and the words “New message”. There is deliberately no unread count in it.
When a call comes in we hand the push service the recipient’s VoIP token, the calling account’s id and a timestamp. The caller’s id is in the payload because iOS requires the call to be reported to the system before the push handler returns, and the phone has to be able to name who is ringing.
Apple cannot read the message: the body we hand over is the same ciphertext we hold, and we have no key for it either. But this is a real disclosure and it should not be softened. Apple’s push service sees which device received something from which account, and when — for messages and for calls. In our own code’s words, it hands Apple a social graph in opaque identifiers. A room message is one push per member whose phone is asleep, so a room’s membership is visible to Apple in the same shape it is visible to us, and for the same reason (section 05). Push is how a message reaches a phone that is asleep; there is no version of that which does not involve Apple.
What a notification shows
Notification previews have three levels — name and text, name only, or just “New message” — and default to the sender’s name only. Previews are gated by a renewable seven-day lease written when you unlock the app for real and deleted when you lock it and on a duress entry; if the lease is missing, expired or unreadable, the notification shows nothing.
Deleting your account deletes the push-token row along with everything else — since 4 August 2026 (section 20).
What stays on your phone
There is no server-side copy of your conversations. Everything in the list below lives on your device only, and we never receive it.
- Your message history, in readable form, in a local database.
- Photos and files you sent or received, decrypted, stored in that same database.
- Drafts you typed and did not send, kept per conversation.
- Reactions, pending edits, a list of message ids already seen so a redelivery cannot duplicate, and an outbox of encrypted messages waiting to send — the same ciphertext we would see, not plaintext.
- Per-conversation notes that never leave the phone: a private nickname, when you last verified a safety number, when a comparison failed, whether an identity ever changed.
- The disappearing-message timer — shared, so setting it sends an encrypted frame to the other phone (to every member’s phone, in a room). It never reaches us in readable form, but it does go on the wire.
- Your call history — who, which direction, audio or video, start, connect, end, missed. Derived locally by each side; never exchanged with the other person and never sent to us.
- For a call that is ringing right now, the decrypted call set-up, which carries network address information. It is deleted the moment the call ends.
- Your list of blocked people.
- Vault items — see below.
- Your own profile: your account id, your display name, your “about” text and your avatar. The card the other person chose to show you is stored the same way.
- Encryption key material — your identity keypair, per-conversation ratchet state, the pinned identity keys of people you talk to, and your prekeys — kept as files in their own directory of the container the app shares with its notification extension, excluded from device backups and re-marked as such every time the store is opened. It is not the iOS Keychain, and deleting the app destroys it.
- In the iOS Keychain: your session token, your app-lock passcode and its settings, the lock’s failure count and cooldown, your read-receipt preference and your screen-capture preference — written so they never sync to iCloud Keychain, never migrate to another device, and are readable only after the phone has been unlocked once since boot.
- In a shared container the notification extension can read, as plain files: your own account id and the display names of the people you talk to (so an incoming call can be named before anything is decrypted); your blocked ids (so a banner from someone you blocked is suppressed); your notification-preview level and the lease marker that arms previews; and two badge counters.
Of those shared files, the account id, the display names and the lease marker are deleted when you lock the app and on a duress entry — which is what stops previews. The blocked-id list is not deleted — only ever rewritten in full — because suppressing notifications has to keep working while the app is closed.
The local database is protected by iOS Data Protection rather than a second layer of app-level encryption — no SQLCipher, no app-layer database key. A deliberate, stated choice in the code, and it means the protection is real only if your phone has a passcode.
Two places plaintext sits outside the database
The notification extension decrypts on arrival, before the app has run, and writes the plaintext to one file per message in a spool — decrypting consumes the message key, so that plaintext is the only surviving copy. Entries are removed only after the app has opened and committed them; if the app is never opened, that plaintext sits on disk.
Previewing a file writes it out. A file preview decrypts the bytes into a temporary directory for as long as the preview is open; the directory is swept every time the module starts, because a force-quit mid-preview would otherwise leave the file behind.
Device backups are a much narrower exception than they were. The app marks its most sensitive files as excluded from iOS backups: the message database — the real and decoy workspaces live inside a single directory that carries the exclusion, so everything SQLite creates beside them, including the journal file, is excluded from the moment it exists; the notification extension’s spool of decrypted plaintext; the directory holding your encryption keys; the temporary directory a voice recording passes through; and the temporary PNG of your own code written for the share sheet. So an iCloud or computer backup should not contain your message text, your photos and files, your drafts, your call history or your vault items — and the keys have never been in one, which is what keeps “lose the phone and the account is gone” true.
“Should not” is doing work in that sentence, so here are the caveats. The exclusion is a flag our code sets on the directory the databases live in — asserted before anything is created there, re-asserted every time a database is opened, and checked by tests that fail any design sliding back to flagging files one by one — but we have not verified on a physical device that every backup pathway honours it: we are stating the mechanism, not promising the outcome. The databases moved into the excluded directory the first time the current version ran; a backup made before then can still contain what the older per-file design let through, and we cannot reach into a backup that already exists. If setting the flag ever fails, the app opens anyway — a failed filesystem attribute must not take your messages down with it — and asserts it again at the next open. (An earlier version of this paragraph described the gap wrongly, twice over — corrected by 5 August 2026; section 20.)
What is still backup-eligible: the small shared files the notification extension reads — your own account id, the display names you hold for the people you talk to, your blocked list, the notification-preview level and its lease marker, and two badge counters. A list of the names you chose for the people you talk to is not nothing. If you would rather Apple could not read even that, turn on Advanced Data Protection, or exclude Tacendum from iCloud Backup in iOS Settings.
Which also means a restore does not bring Tacendum back. Restoring a backup onto a new phone restores neither the account nor the conversations: the keys and the message database were not in the backup. Section 02 sets out what follows: no recovery, no deletion through the app, a new id, and nobody told.
Disappearing messages
Each conversation with one person has a shared timer that either side can set, with the newest setting winning on both phones. A room works differently: every member holds their own timer, and the room uses the shortest one anybody has set — anyone can make messages disappear sooner; nobody can make them last longer on anyone else’s phone. The choices are the whole of it: Off, one hour, one day, one week. There is nothing longer and no arbitrary number; if you need a retention rule measured in months, the app cannot express one. A message you receive starts its clock when you read it; a message you send starts its clock at send. When it expires, the message is deleted together with its attachments and its reactions, in one transaction.
The sweep runs when you open a conversation — not when the app comes to the front, whatever a comment in our own code still says, and not on a background timer. So an expired message is removed the next time the app is used to read something, not at the instant the timer elapses.
Disappearing messages are cooperative deletion between honest apps — two in a one-to-one conversation, up to twelve in a room, where any one copy not deleting itself is enough. They cannot stop the other person photographing the screen, and they cannot stop someone running a modified build. It is an honest limit, not a guarantee.
The shared vault
The vault holds things you keep re-typing to one person — a door code, a Wi-Fi password, a login. It is stored and sent exactly like a message: same encryption, same database, same lock on the phone. It is not a password manager — no separate password, no recovery key — and the title and body are ordinary text columns in the same database as your messages.
Three things to know before you use it:
- Vault items do not disappear on the timer. The expiry sweep structurally cannot reach them; an item stays until one of you removes it — a deliberate increase in retention relative to everything else in the app.
- Saving or removing an item also leaves a notice in the chat, and that notice still carries the value. Removing the vault item does not remove that second copy; it goes when the notice goes, or when a timer takes it.
- Copy puts the value on the iPhone pasteboard, where every app on the phone — and every device on the same iCloud account, through Universal Clipboard — can read it. The app clears it about a minute later, a software timer: force-quitting first leaves the value there, and clearing cannot un-read what was already read. The clear checks the pasteboard first so it never wipes something you copied in between — that check is a read, so iOS may show “Tacendum wants to paste” roughly a minute after a Copy.
Screenshots, and when the screen is being watched
If you take a screenshot while a conversation is on screen, the app tells the other person — everyone in it, if it is a room. Automatically, the moment it happens, with no setting that turns it off: a disclosure which can be switched off is not a disclosure. An iPhone does not let any app prevent a screenshot, so the app says one was taken.
One case where it does not fire: in a room with somebody you have blocked, a screenshot you take notifies nobody at all — not the blocked member, and not the rest of the room. Blocking refuses that person’s copy, and the whole notice is abandoned rather than sent to everyone except them, because a notice that skipped exactly one person would tell the room who you blocked. If a screenshot being announced is what you are relying on, that is the gap.
That notice is a message like any other: encrypted on your phone, riding inside the same envelope as your words, and raising a notification rather than arriving silently. It reaches the other person and not us. It is not sent when the screen was covered by the app-switcher shield at the moment of capture — that screenshot contains no conversation — and it is never sent to someone you have blocked.
Separately, while it is running the app observes whether your screen is being recorded, mirrored or sent to another display. That state stays on your device — never transmitted, and the other person is not told. It is used for one thing: while capture is active the app blanks conversation content and dismisses the keyboard, so the recording captures nothing. The blanking is on by default, can be turned off, and fails closed if the preference cannot be read. When the app goes to the background it covers the screen before iOS takes its app-switcher snapshot, tearing down the keyboard first so the predictive-text bar cannot echo what you just typed.
Blocking
Blocking is enforced entirely on your phone. There is no server endpoint for it and no server-side record of who blocked whom — a server-side block list would be a social graph on our servers. While someone is blocked, this device sends them nothing at all: no message, reaction, edit, retraction, screenshot notice, profile card, vault item, read receipt, call signal or queued envelope. The design property is that a blocked person cannot tell.
The consequences: a blocked person can still queue ciphertext for you on our servers and can still consume your single-use prekeys; you simply never see any of it. The block lives in this app on this phone, in this workspace, and does not survive a reinstall or an account deletion. The blocked person is never told, by design.
In a room you share with someone you have blocked, that last property cannot hold. The room goes read-only for you — your phone sends nothing there — rather than quietly sending to everyone except them. Nor can a block make you invisible in a room: the other people quote you and react to you, and they read their own copies. Section 05 is the rest of it.
Read receipts
On by default, and you can turn them off. The preference lives in the Keychain, so it survives a wipe of the workspace and never exists in the decoy workspace. When they are off nothing is sent and nothing is marked — a receipt withheld today is not emitted later if you turn the setting back on. Rooms send none at all, whatever this setting says.
The app lock, and the decoy workspace
The app lock allows five attempts, then imposes a cooldown starting at thirty seconds and doubling to a ceiling of fifteen minutes. That cooldown state lives in the Keychain, so relaunching the app cannot reset it. There is no wipe-on-failure — nothing is destroyed by wrong guesses.
The passcode is stored in the Keychain as the digits you set. It is not hashed and not key-derived; the Keychain is the protection.
A duress entry at the lock screen opens a separate, decoy workspace. There is no second secret to choose, to remember or to lose, and no separate duress code is stored anywhere.
The decoy workspace is fabricated. Its conversations and its vault items are generated at the moment you set the passcode, from a bundled corpus plus the operating system’s randomness. Nothing is copied from your real workspace, with one deliberate exception: your own profile is real, because a decoy that renamed you would give the act away. Your account id, display name, “about” line and avatar are carried across. Nothing about anyone you actually talk to is.
A duress session sends nothing. Changing the passcode, the auto-lock interval or the screen-capture setting does nothing; creating or deleting an account sends no packet; read receipts and screenshot notices are not transmitted; and the settings screen shows defaults rather than your real preferences. One honest limit: the notification extension keeps counting real arrivals, so the app icon’s badge can still move during a duress session.
Permissions the app asks for
Camera — for video calls, and when you take a photo to send. Taking a photo inside Tacendum does not save it back to your photo library.
Microphone — for calls.
Photo library — when you choose a photo to send, and when you add someone by picking a saved image of their code, since there is no directory to look anyone up in.
Location — only when you choose to share a place. The app takes a single fix, puts the bare coordinates inside the encrypted envelope, and sends them to that one person. No map tile is ever fetched — a tile request would tell a map server where your contact is; the map opens in Apple Maps only if someone deliberately taps the card.
Photo metadata. The app asks the system picker for a downscaled copy, and where the picker honours that the photo is re-encoded and most embedded metadata is dropped. That is not a guarantee: the picker will not re-encode some formats, so a photo that is already small enough can be sent through unchanged, with its EXIF — including GPS coordinates — intact. The app itself does not strip metadata or re-encode; assume yours is not stripped. Files sent through the file picker are never re-encoded; they are copied into the app and encrypted as they are.
The command-line client and the MCP server
There is also a command-line client, for machines that need to send notifications, and a local MCP server that lets an assistant read messages already synchronised onto that machine. This page covers them, and a computer is not an iPhone: there is no Data Protection, no Keychain, and no app lock.
- An account there is the same thing — a keypair — and the private key is an ordinary file, identity.json, under $TACENDUM_HOME (by default ~/.tacendum). Files are written 0600 inside directories written 0700. Anyone who can read that directory is that account.
- Decrypted message history is written to disk as a plain text-based log under $TACENDUM_HOME/state/. It is kept for thirty days, and the body of a message is redacted twenty-four hours after it is marked read. The caveat that makes those numbers honest: the passes that enforce them run only when a command runs — there is no background daemon, so a spool nothing ever visits keeps what it has. Nothing on a computer is excluded from that computer’s backups the way the iPhone key store is.
- The MCP server runs on your machine, talks to nothing else, and cannot transmit on your behalf. It is no-send rather than read-only: of its three tools, two read and one writes locally — marking messages read, which starts the twenty-four-hour redaction clock.
- What our servers receive from these clients is what they receive from a phone — the same envelopes, the same metadata in section 03 — and nothing more.
What we never collect
This list is about us — what never reaches our servers. It is not a list of everything the app does. Some things happen entirely between two phones and never touch us: the screenshot notice in section 08 is the clearest example, and “we never collect it” is not the same sentence as “nobody is told.”
- A name. No name exists in the account model. An email address or a username is a different thing and lives in section 02 and section 04: it exists only if you link one, and what we hold is a keyed scrambling, never the address or name itself. The one qualification is the residue from the old SMS registration described in section 02.
- Your contacts. There is no contact upload: your address book is never read and never transmitted, and nothing lets anyone hand us a list to match. The one lookup that exists (section 02) takes a single identifier typed by hand and answers only for an owner who chose to be found.
- Profile fields. No display names, profile photos or “about” text exist as server-side fields. They exist only as ciphertext we cannot tell apart from any other message. A username is not a profile field: it is a scrambled finding label held on our side (section 02), it is never shown in your chats, and it is a different thing from the name you show the people you talk to.
- A directory. There is nothing to browse and no running service that could list our users; the single-identifier lookup in section 02 is the exact scope of that claim.
- Your location. Coordinates you share travel end-to-end encrypted to one person, and no map server is contacted.
- Your block list, your nicknames, your call history or your read state. All local. We put no unread count on a push at all: the only number our servers could offer is the depth of the delivery queue, which would be wrong, and the right number is one only your own device can compute.
- Call quality or network diagnostics. Nothing about the quality or the network shape of a call — bitrates, packet loss, jitter, candidate addresses — is transmitted to us or to the other side. This bullet used to say “call statistics” flatly, and that became wrong on 13 August 2026: a finished call now reports its outcome, its set-up time and its length to us, with nobody’s account id on the figures. That is set out in full in section 06, and the correction is in section 20.
- Device identifiers, advertising identifiers, analytics, crash reports or telemetry. No analytics SDK, crash reporter, attribution or advertising SDK, or distributed-tracing agent anywhere in the app or the servers; a repository-wide search for the usual names finds nothing. The only telemetry in this project is our infrastructure toolkit’s deploy-time report of which building blocks a template used — run on our machine, no user data.
- Payment information. There is no payment processor anywhere in the app, the servers or this website.
Reporting and moderation, stated exactly
There is a Report flow in the app — section 04 sets out exactly what a report contains, what it cannot contain, and the 180 days it is kept. There is no server-side block list — blocking is entirely on your phone and we hold no record of it — and no administrative endpoint anywhere in our API that can suspend or delete somebody else’s account. The accounts table is still our own database, though, and rows can be removed from it by hand — an exceptional act rather than a moderation system; section 18 describes the one situation where we commit to doing it, and section 02 what we will not do it on the strength of. (An earlier version of this page overstated this as “we cannot switch an account off” — section 20.) Finally, mail to hello@tacendum.com — and anything attached to it — is a record in our mailbox for as long as we keep the mail; we cannot verify a claim about an encrypted conversation, and can read only what someone chose to send us. See the Terms for what that means in practice.
How long we keep things
- Account row: account id, public keys
- until the account is deleted — indefinitely if it cannot be
- Identity-key claim
- until the account is deleted — permanent if tombstoned
- Sign-in challenge
- 120 seconds, or the moment it is used
- Session token digest
- 30 days — or sign-out, deletion, or a new sign-in
- Live-connection ticket (stored as its value)
- 60 seconds, single use
- Single-use prekeys
- until handed out, re-uploaded, or deletion
- Queued message (from, to, time, ciphertext)
- deleted when the recipient’s device acknowledges it; otherwise 30 days
- Attachment ciphertext
- 30 days from upload, plus up to 7 days as a superseded copy
- Upload and download links
- 10 minutes
- Live-connection row
- until the disconnect is observed
- Push-token row (Apple device tokens)
- 90 days from the last refresh, or immediately when you delete your account
- Rate-limit counters (IP, account id, account pair)
- the counting window plus 1 hour — about 1 hour, about 2 for relay credentials, push-token writes and abuse reports
- Consent record (your account id, an AI agent’s account id)
- no expiry — until you withdraw it, or delete your account. The only record here with no clock on it other than a tombstoned key claim — section 04
- Call report de-duplication row (two hashes, no readable field)
- 8 days
- Call outcome counters and set-up times, labelled direct/room, audio/video and how the call ended, with no account id
- held as monitoring figures by our infrastructure provider — up to 15 months, progressively coarsened; they cannot be deleted one at a time — section 06
- Activity row (unsalted hash of your account id, day, hour)
- 35 days
- Abuse report (account ids, category, any messages you chose to attach)
- 180 days
- Application and gateway access logs
- 90 days
- Attachment storage access logs (address + object id)
- 30 days — matched to the attachment it describes; see section 04
- Relay session log on the relay host
- 7 days, rotated daily, never centrally collected
- Relay boot diagnostics
- 14 days
- Website firewall request sample (includes source IP)
- a few hours, held by our infrastructure provider
- Waitlist email address
- no expiry yet; removed by hand on request; 24-month auto-expiry committed by 31 December 2026, whether or not anything is ever sent, and deletion of the list within 30 days of the announcement — section 12
- Continuous database backups
- up to 35 days after a row is deleted
Every one of our databases has point-in-time recovery switched on — a safety net against our own mistakes, with a price: for up to 35 days after a row is deleted, it remains restorable from continuous backups held by our infrastructure provider. Deletion is immediate in the live database and takes up to 35 days to become final.
The short expiries are enforced twice over: our code refuses to serve an expired row the moment it expires, and the database reaps the row afterwards — best-effort, lagging by up to about forty-eight hours. So “expires after 30 days” means unusable at thirty days and physically gone shortly after, not to the second; the same holds for the 120-second challenge and the 60-second ticket.
The tables, the buckets and the log groups are configured so that dismantling our infrastructure does not delete them: removing the data is a deliberate act, not a side effect of shutting the service down. Section 13 says what happens to it if the company does not continue.
Deleting your account
In the app, deleting your account is the only exit. There is no sign-out in the app, because your conversations exist only on your device: “sign out and come back later” is a promise the architecture cannot keep, so it is not offered. Deletion is irreversible, and it needs a working connection — an attempt made offline fails and destroys nothing. It also needs your key, so if the key is gone the account cannot be deleted from the app at all (section 02).
One condition, if you run machines. An account that has adopted integration accounts into a crew (section 02) is refused deletion until each one is retired by its id, and the refusal comes before anything is destroyed — nothing of yours is touched by an attempt that is turned down. The reason is the same absent index as everywhere else on this page: our servers cannot list the machines an account owns, so they cannot tear them down for you, and deleting the owner anyway would leave machines nobody could ever revoke.
Deletion retires the account on our servers first. In order, it removes: your account row and the claim on your identity key — which releases the key unless it has been tombstoned, and goes first so a refusal can never follow a destruction; then your activity rows, every message queued for you, every consent record you wrote and the counter that tracked them, your single-use prekeys, your push-token row, and your live-connection row; then every session belonging to the account, the calling one included. Only once that has succeeded does the app wipe every local table, reset the encryption key store, delete the session token from the Keychain, clear all app-lock state, and wipe the decoy workspace file.
This is the most complete erasure available: it reaches the phone, which nothing we do can. It is not the only way an account row can go — section 09 and section 18 describe the exceptional hand-deletion, which removes exactly the same server-side set; the two routes have matched since 4 August 2026 (section 20).
What deletion does not erase
This list is complete as far as we know:
- Messages you sent that are still waiting for someone else. Those rows are filed under the recipient, so your account id stays on them until their phone acknowledges receipt or the thirty-day expiry passes.
- Attachments you uploaded. Deleting an account does not delete blobs; they age out on the storage schedule, up to thirty days. What remains is ciphertext whose keys died with the chats.
- Rate-limit counters keyed by your account id — sends, tickets, relay credentials, push tokens, abuse reports, upload links, download links, session revocations, the deletion itself — and, if you had just fetched someone’s keys, the counter naming both of you. Up to the counting window plus an hour.
- A tombstoned identity-key claim. Integration accounts are tombstoned both when an owner revokes them and when they delete themselves; that row is permanent by design and survives deletion, and there is no code anywhere that clears one.
- Log lines carrying your account id. Up to ninety days. Ten distinct events write one, including the line recording the deletion itself.
- Attachment storage access-log entries. Up to thirty days — matched to the attachment they describe rather than to the log lines above, so the record of a fetch no longer outlives the file it was about.
- Consent records other people wrote about your machines, and this is the only thing on this list with no expiry at all. If you ran an integration account and someone consented to it, that row lives in their half of the table, not yours — it is their decision, recorded — and deleting your account does not remove it. It cannot: nothing in our system can list the consents pointing at a given agent, deliberately, so there is nothing to find and sweep. What is left is inert — every check re-reads the account row, which is gone, so the permission grants nothing — but it is durable, and it lasts until each person who wrote one withdraws it or deletes their own account. Your own consent records, the ones you wrote, are removed (section 04).
- The de-duplication row for a call report, up to eight days, and the outcome counters and set-up times themselves, which carry no account id and cannot be deleted individually (section 06).
- An abuse report, in either direction. A report you filed, and any report filed about you, sits in its own write-only table for its hundred and eighty days, and deletion does not reach into it — deliberately, because an account that could erase the reports about itself by deleting and re-registering would defeat the one record that shows a repeat pattern (section 04).
- Anything inside the thirty-five-day backup window described above.
- An already-open live connection, which keeps its socket until it closes — though its routing row is gone.
- A legacy phone-claim row, if you registered by SMS before that path was removed. Nothing deletes those; write to us.
- Copies of messages already delivered to the other person’s phone. Those are theirs, on their device, entirely outside our reach. Deleting your account does not and cannot reach into someone else’s conversation.
The website and the waitlist
tacendum.com is entirely separate from the messenger: nothing on this website talks to the messaging service, and no account exists here.
Reading the site loads nothing from anywhere else: no third-party fonts, scripts, analytics or embedded media. Its content-security policy permits exactly one outside origin — awswaf.com, our own infrastructure provider’s spam filter, described below — and blocks everything else even if it were ever added by mistake. Nothing is written to local storage. Request logging on our content delivery network is deliberately switched off, and the bucket that holds the pages has no access logging. Domain ownership is proved to search engines with a DNS record rather than a page tag, so nothing lands on the page.
If you use the waitlist form
Pressing “Notify me” stores exactly two things: your email address, lowercased and trimmed, and the time you submitted it. No IP address, no browser details, no name, no referrer, no country. The form carries a hidden field that only automated submitters fill in; when it is filled in the submission is discarded without being stored. A repeat submission returns the same success as a new one, so the form cannot be used to test whether an address is already on the list.
The purpose is one email: the one that says the app is available. Nothing has been sent. Our sending domain is configured and its signing records are published, which is groundwork, not permission.
What is true today. Your address sits in a database with no expiry and no unsubscribe link, because nothing has been sent for there to be a link in. It is removed only by hand, when someone asks. Write to hello@tacendum.com and we will delete it; as with everything else, the deleted row remains restorable from backups for up to thirty-five days after that.
What we commit to, and by when. An automatic expiry on stored addresses, so no address is kept longer than twenty-four months from the day it was submitted — configured by 31 December 2026, whether or not any email has been sent and whether or not one ever is. Until the automatic expiry exists, we apply the twenty-four-month rule by hand. And deletion of the whole list within thirty days after the announcement goes out — and if we ever decide there will be no launch email at all, we delete the list then rather than keep it. Until this page says the expiry is in place, assume it is not.
What we commit to before anything is sent. A working unsubscribe link in the message. It will keep working for at least thirty days after the message goes out. Using it will cost nothing and will require nothing from you beyond your address and the fact that you want out — no account, no reason, no form. And we will act on it within ten business days.
What we are not promising. That the email will ever be sent. United States law requires a commercial email to carry a valid physical postal address for the sender, inside the message. We do not publish a postal address on this website and we are not going to. Before any send we would obtain a registered mailbox to put in the message; if that has not happened, the message does not go out, and your address is deleted on the twenty-four-month expiry rather than used.
The spam check on the form
Pressing “Notify me” is the one moment this site can load anything from outside itself. Our infrastructure provider’s firewall decides whether the submission could have come from a real browser. Most of the time it settles that on its own and you notice nothing. When it cannot, your browser fetches a small script from awswaf.com — the only thing this site ever loads from elsewhere — which answers a silent check in the background. There is also a flood rule: if a large number of submissions arrive from the same network address in a short window, that address gets a visible puzzle instead of the silent check. The rule counts addresses, not email addresses; nothing about it looks at what you typed. Both are the provider’s, not ours, and neither runs unless you press the button.
Answering either one leaves a cookie on this site named aws-waf-token, scoped to tacendum.com. It is set by the firewall, it records that a check was passed and when, and it is readable only by the firewall — it holds no account, no address and no identifier of ours, and nothing on this site reads it. It is the only cookie this site can set.
That script also sends the provider its own measurements of your browser while it runs — the signals it uses to tell a browser from a script. We do not see them, we cannot read them, and we ask for nothing beyond the yes-or-no answer of whether the submission should go through.
The firewall’s request sample is broader than the form. Sampling is switched on at the level of the whole rule set, not only on the individual rules, and the site’s default action is to allow. Requests handled by that default action are sampled as well, and every sampled record carries a source IP address. So ordinary reading of tacendum.com — not just a form submission — can leave your address in that sample for a few hours. It is held by the provider, we do not export it, and it expires on its own. (An earlier version of this page said page reads entered no sample — corrected by 5 August 2026; section 20.)
Do Not Track and Global Privacy Control
This site does not respond to Do Not Track or Global Privacy Control because there is nothing to switch off: no tracking across sites, no sale or sharing of personal information, one cookie (the firewall token above), and one third party (the spam check, run by our infrastructure provider as our service provider, on instructions that do not include following you anywhere).
Who else touches this
These are the parties involved today.
Amazon Web Services
AWS is our sole infrastructure provider and processes everything described above. The services in the path: DynamoDB for the databases; S3 for encrypted attachments, the website’s files and the attachment access logs; Lambda for the code; API Gateway for the request and connection interfaces; CloudFront for delivering this site and attachment ciphertext; AWS WAF for the spam check; CloudWatch Logs, Metrics and Alarms for operations; SNS, carrying alarm email to us and nothing else; SES, for the waitlist launch email and, since 29 August 2026, the verification and recovery codes described just below; EC2 and Auto Scaling, running the call relay; Route 53 and Certificate Manager for the domain and its certificates; and Secrets Manager.
On encryption at rest: all three storage buckets use the provider’s own bucket-level encryption, and the databases use the provider’s default key; a managed key-service key appears only on the topics that carry our alarm email. In every case the keys are managed by the provider rather than held only by us — the sentence that matters, repeated in section 17.
Four secrets sit in Secrets Manager: our Apple push signing key, the private key that signs attachment download links, and the relay’s shared authentication secret and user salt. They are fetched at runtime by identifier rather than injected into function configuration; none is user data. One further shared value does not follow that pattern: the website’s waitlist function holds, in its plain configuration, the secret our delivery network stamps on requests so the function can tell they came from us. It guards no user content and opens nothing beyond the ability to reach the waitlist writer.
Public access to the storage buckets is blocked, TLS is enforced on them, and data is encrypted at rest and in transit.
Amazon SES
Amazon SES — delivers email verification and recovery codes; sees the address at send time; identifier-bearing event logging is off, and the bounce list it keeps for us is keyed by the same scrambling, not the address.
Apple
The app is distributed through Apple, so Apple can see that you downloaded it. Apple provides the Keychain and the file protection that guard the app’s on-device data, and holds your device backup if you use iCloud — which, as section 08 sets out, is not supposed to include your Tacendum messages any more, though it does include a few small shared files. And Apple’s push service is a relay for message and call notifications, receiving what section 07 sets out.
Let’s Encrypt / ISRG
The relay’s TLS certificate is obtained from Let’s Encrypt using a DNS-based challenge. That sends Let’s Encrypt the relay’s hostname and an operator contact address for expiry notices, and publishes the hostname in public certificate transparency logs. No user data is involved.
At boot only
When a relay instance starts it fetches its pinned relay image from Docker Hub and its operating-system packages from the distribution’s repositories, which discloses the instance’s address to those services. No user data is involved, and this happens before any phone can connect.
If the company changes hands or stops
There is no such event today and none planned, but a list that did not cover it would stop being true the moment one happened. If Mirana Technologies Inc. were acquired, merged, reorganised, sold its assets, or wound up, the data described on this page could pass to whoever took it on. Section 10 says the tables and buckets are configured to survive our infrastructure being dismantled, which makes this the more important sentence, not the less: the data can outlive the service.
Our commitment is the part we actually control. In any transfer we negotiate, we will require the buyer to take the data subject to this policy as it stands, and to post any material change here first, on the timetable in section 20. That timetable is not procedure for its own sake: the thirty days are your opportunity to opt out by the one means that fully works here — deleting your account before the change takes effect, which removes what there would have been to transfer. What we cannot promise is the same outcome in a court-supervised wind-up: in a bankruptcy or a receivership an estate can sell assets, and a statement on a web page is not a covenant that binds it. If you would rather not find out, deleting your account is available now and is described in section 11.
No analytics vendor, crash-reporting vendor, advertising network, font or script network, third-party relay vendor, or payment processor appears anywhere in the app, the servers or this website — section 09 is the full negative list. We do not sell personal information and we do not share it for advertising, and we have not done either in the twelve months before the date at the top of this page.
Where it is processed
Everything we store — databases, attachment storage, logs and the call relay — is held in the United States, in the AWS us-east-1 region in Northern Virginia. One caveat: the region is a property of the deployment, not a value in the code, so it is a statement about the deployment running today rather than something verifiable from source. If it ever changes, this page changes with it.
This website and the attachment store are delivered from a content delivery network whose edge locations are limited to North America, Europe and Israel. It serves from an edge near you and records no request logs for us.
Nothing in the product restricts registration or use by country. Registration is one tap on a keypair your phone generates; there is no country field, no number to enter and no geographic gate anywhere in the code. If you use Tacendum from outside the United States, the data described on this page is processed in the United States.
For people in the European Union and the United Kingdom, our position is worth stating exactly rather than gestured at. European law reaches a company like ours only if we offer the service to people there or monitor them, and merely being reachable from Europe is not offering. Tacendum is marketed nowhere, English-only, free, has no country field, no European presence and nothing in it that envisages a European user. On that reading the GDPR does not apply to it today. (An earlier version rested this conclusion on a registration premise that no longer exists — corrected by 5 August 2026; section 20.)
We are stating a position, not proving one, so here is what is missing if it is wrong: no standard contractual clauses, no adequacy decision we are relying on, and no formal transfer mechanism of any kind.
The rest of that package is absent for the same reason, and naming it is better than leaving a reader to discover it. We have not appointed a representative in the European Union or in the United Kingdom — that obligation attaches to a controller that offers its service there, which on the reading above we do not. We have not appointed a data protection officer; on our assessment none is required, since we do not monitor people on a large scale and the only special-category data in the system is content we cannot read. There is no lead supervisory authority, because we have no establishment in Europe — so if you want to complain, the authority to approach is the one where you live, and you do not need our permission to do it. The same is true of the United Kingdom’s Information Commissioner. If that matters to you, weigh it before you create an account.
Why we are allowed to
Each item above is collected for a single stated purpose, and for nothing else:
- Your account id and public keys: so an account can exist and someone can start an encrypted conversation with you.
- The identity-key claim: so that exactly one account can ever hold a given key, and so signing in again from the same device returns the same account.
- The sign-in challenge and the session token digest: to prove a request comes from the holder of the key, and to authenticate the requests that follow.
- Message envelopes: to deliver a message to a phone that may be offline.
- The live-connection row: to route a message to your phone right now.
- Attachment storage: to carry a file that is too large for a message.
- Push tokens: to wake your phone for a message or a call. Nothing else is ever pushed.
- Relay credentials: to let a call connect without either party learning the other’s address.
- Rate-limit counters and logs: to keep the service standing up, to stop abuse, and to fix it when it breaks.
- Waitlist email: to send one launch announcement, subject to section 12.
None of it is used for profiling, advertising, ranking or resale. We do not use automated decision-making that produces legal or similarly significant effects, because there is nothing to decide about: the servers hold an id, a creation time and public keys.
Mirana Technologies Inc. is the controller of this data. Where a privacy law applies to you, the basis for the processing above is performing the service you asked for, together with our legitimate interest in keeping that service available and free from abuse — which is what the rate-limit counters and the operational logs are for. For the waitlist address, the basis is your consent, given by typing it in, and you can withdraw it at any time by writing to us.
Your rights
Privacy laws in California, Virginia, Colorado, Connecticut and a growing number of other states, in Canada, and in Europe give people rights over their personal information: to know what is held, to get a copy, to correct it, to delete it, to object to or restrict some processing, and to appeal a refusal. On revenue and volume we do not currently meet the threshold that makes a company a “business” under the California Consumer Privacy Act, and several other state acts have similar floors — but we are not relying on that. The rights below are offered to everyone who asks, wherever they live, and the process is the same in each case.
Read this before the procedure, because it changes what the procedure can do. An account here is an anonymous keypair. We hold no name for it. If you linked an email address, we hold a scrambled form of it that lets the app prove you still hold that inbox — which is exactly what account recovery uses, and exactly why recovery recovers the account grouping and discoverability only, never your messages or your keys — but nothing you could cite to us by mail to prove an account is yours. The only thing that proves an account is yours is possession of its private key, which is what the app does at sign-in — and we have not built a way for you to do that outside the app.
So for account data, most verified-request machinery cannot be honoured. We will not hand account data to someone who merely knows an account id, and we will not delete an account on that basis either, because an account id is a thing people hand out on purpose: doing so would turn this policy into a lookup service against our own users, and a deletion into a way of taking someone’s account away from them. California’s law says squarely that a business does not have to collect more information about you, keep information it would otherwise delete, or re-identify anything, purely in order to verify a request. That is the position we are in.
What can be done is the thing that actually works: delete the account from the device. That is not a lesser substitute. It removes the row on our servers, the identity-key claim, the queued messages, the prekeys and every session — and it wipes the phone as well, which is the part no request to us could ever reach. Section 11 sets out exactly what it erases and the thirteen things it does not.
We can also remove rows from our own database by hand, and there are three cases where we will: a legacy phone-claim row (section 02), a waitlist address, and a parent’s deletion request about a child (section 18).
For the waitlist, none of this applies. An email address is an identifier we can act on, and we will.
How to make a request, and how long we take
Write to hello@tacendum.com. Say what you want and, if it concerns the waitlist, write from the address in question. Email is the only intake channel, which is allowed for a business like this one: we operate entirely online and deal with you directly, with no shop, no phone line and no account of yours holding a contact detail we could use instead.
- We acknowledge within ten business days, and that acknowledgement tells you how we intend to verify the request and how long we expect to take.
- We answer substantively within forty-five days. Where a request is genuinely complex we may extend once, by up to a further forty-five days, and we will tell you inside the first forty-five days that we are doing it and why. That is the California window; it is also inside what Virginia, Colorado and Connecticut require, so it is the window we use for everyone.
- There is no charge for the first two requests in a twelve-month period. We will not charge for a further one without telling you first, and we will not use “manifestly unfounded” as a way of declining to answer awkward mail.
Verification, and authorised agents
For a waitlist request we verify by replying to the address itself: if you can receive that reply, you control the address. For an account request there is no verification method we can offer, for the reason set out above. We will tell you that in writing, with the reason, rather than ask you for identity documents we have nothing to check them against — and to be clear, we will never ask you to send us a photograph of an identity document, because we hold nothing that could match one and collecting it would be a fresh privacy harm rather than a check.
You may use an authorised agent to make a request for you, as California law permits. Send us the agent’s written permission signed by you. The same limits apply to the agent that apply to you: an agent cannot verify an anonymous keypair either.
Appeals
If we refuse a request, you can appeal, and the laws of Virginia, Colorado and Connecticut require us to tell you how.
Reply to the refusal, or write to hello@tacendum.com with the word appeal in the subject line. It is reviewed afresh rather than rubber-stamped, and by a different person wherever the company has one — we are small enough that promising a second reviewer unconditionally would be a promise we might not be able to keep. We will give you a written decision within forty-five days, with our reasons.
If we deny the appeal, you can complain to your state regulator, and our denial will say so and point you at the route. In practice that means the Office of the Attorney General in Virginia, Colorado or Connecticut, the California Privacy Protection Agency or the California Attorney General if you are in California, and the equivalent office in any other state with a comprehensive privacy act. You do not need to go through us first, and nothing here waives anything.
No penalty for asking
We will not discriminate against you for exercising any of these rights. We will not deny you the service, charge you a different price or rate, give you a different level or quality of service, or suggest that you will get any of those, because you made a request. Tacendum costs nothing and works the same either way.
What we hold, in the statute’s own categories
California’s law asks for the inventory to be mapped onto its own list of categories, so here it is in full. Everything named came from you or your device, is used only for the purpose in section 15, and is disclosed only to the parties in section 13 — our infrastructure provider, and Apple for push. None of it is sold or shared for advertising.
- Identifiers
- your account id; the Apple device tokens if your device registered one; a keyed scrambling of an email address or username if you linked one (section 04); an email address if you use the waitlist; IP addresses in the five places named in section 04
- Internet or network activity
- message envelopes (which account, to which account, when, and whether it opens a conversation); whether a live connection exists; route names and status codes in access logs; the firewall’s short request sample
- Audio, electronic, visual or similar information
- message bodies and attachments, which pass through us and are stored briefly as ciphertext we cannot read
- Sensitive personal information
- the contents of your communications, in the same encrypted form. We use it only to deliver it, never to infer anything about you, and never for any purpose that would trigger a right to limit its use
- Precise geolocation
- none. A location you share is encrypted to one person and never reaches us
- Personal records, protected classifications, commercial information, biometric information, professional or employment information, education information, inferences
- none, in any of these categories. We hold no profile of you and generate none
Deletion, access, correction
Deletion. For the app, delete your account inside the app. For the waitlist, write to us and we will remove the address by hand; there is no automated route today.
Access and export. There is no automated export tool, largely because there is very little to export and most of it is already yours: your conversations are on your phone and we have never held them. What our servers can hold for an account is exactly the list in section 04, and that list is the access response — it is the same for every account.
Correction. There is essentially nothing to correct. Your account row is an id, a creation time and your own public keys — we hold no fact about you that could be wrong. The one exception is a legacy phone-claim row from the old SMS registration; write in and we will remove it.
Objection, restriction and portability depend on where you live and are handled through the same address and the same windows. Where the law gives you a right to complain to a supervisory authority — a state Attorney General, the California Privacy Protection Agency, a European data protection authority, the Office of the Privacy Commissioner of Canada, the United Kingdom’s Information Commissioner — you can do that directly, and section 14 explains why we cannot point you at a single one.
Security
- Messages and calls are end-to-end encrypted with the Signal protocol, including a post-quantum key exchange. Private keys are generated on your phone and never uploaded, and the file store holding them is excluded from device backups.
- Separately from that store, the Keychain holds your session token, your app-lock passcode and settings, the lock’s failure state and two preferences. Those items never sync to iCloud Keychain and never migrate to another device, and are readable only after the phone has been unlocked once since boot.
- The app can show a safety number for each conversation with one person, pins a peer’s identity key the first time it sees it, and records locally when you last confirmed a match, when a comparison failed, and when a peer’s identity changed. A room has no safety number of its own — you compare member by member (section 05). A changed safety number has no innocent explanation in this design — section 02.
- Session tokens are stored only as digests. The one exception is the sixty-second single-use connection ticket, which is stored as its value and destroyed on first use.
- There are exactly two unauthenticated routes — the two sign-in endpoints — and both are rate-limited per source address (a removed third, a deployment probe, is described in section 04). Almost every authenticated endpoint is limited per account — two are not: the “who am I” check the app uses to validate a session, and the key upload, which sit behind only the service-wide request throttle. The key upload cannot replace an identity key, which is immutable once set.
- No code we run on the internet can query or scan the accounts table, and that table has no index — enforced by a test over the infrastructure definition, not just by intent. Nothing in the running system can enumerate accounts, and “is this key registered” can only be asked one caller-supplied key at a time. It is not a claim that nobody holding administrative credentials could read our own database — section 02.
- Our signing keys are fetched at runtime by identifier rather than injected into function configuration, with the one exception named in section 13.
- The app lock allows five attempts then backs off to a fifteen-minute cooldown held in the Keychain, and the app blanks conversations during screen capture and covers itself before the app-switcher snapshot.
- Data is encrypted at rest and in transit. Connections to this site are HTTPS-only with strict transport security.
- Tacendum is licensed AGPL-3.0-only. The source is not published yet. It goes up at launch, at no charge, tagged per release; today github.com/MiranaTechs/Tacendum is a reserved and empty repository — it answers, and it serves nothing. Until it is up the written offer is the route, not a supplement: write to hello@tacendum.com naming the version you have and we send you its source. Settings → About names the build you are holding and links the source for that build — that pointer, rather than anything typed on this page, is the one to trust. The Terms set out the arrangement.
Limits worth naming. The app-lock passcode is stored in the Keychain as the digits you set — not hashed, not key-derived. The local database has no app-level encryption; it relies on iOS Data Protection, which means it relies on your phone having a passcode. It is marked excluded from iPhone backups, with the caveats section 08 sets out. Someone with sufficient internal access to our infrastructure could take attachment data out of storage — it would remain ciphertext they cannot open, but they could take it. Encryption at rest uses keys managed by our infrastructure provider rather than keys held only by us. And no independent security audit of Tacendum has been published. Source shows you how the system is designed; it does not prove that the build in your hand or the service you connect to was made from it.
If there is a breach
If a breach affects your data, we will investigate, contain it and notify people and regulators as the law requires. Concretely:
- We will notify affected people without unreasonable delay, and no later than thirty days after we discover a breach — discovery, not confirmation, because discovery is the clock several states actually run and the later trigger is the one that gets a company caught inside its own promise. Unless law enforcement asks us in writing to hold off, in which case we notify as soon as they release us.
- We will notify regulators on their own clocks — within seventy-two hours to a European supervisory authority where that regime applies, and to the relevant state Attorneys General where a state requires it.
- The channel is a problem and we will not paper over it. For app accounts we hold no name and no address we can write to — a linked email is held only as a scrambling we cannot reverse, and the code we send you arrives only because you typed the address into the app a moment earlier — and the only pushes our servers can send are the ones another user’s message or call causes; there is no operator broadcast in the system. So the notice would have to be a substitute one, and the law is specific about what that takes: email to everyone whose address we hold in the clear, which is the waitlist and no one else, a conspicuous notice on this website kept up for at least thirty days, and notification to major statewide media. We commit to all three, and to making the notice the first thing on the home page. (An earlier version committed to less — corrected by 5 August 2026; section 20.)
- Waitlist subscribers we can email, and would. A breach notice is not a marketing message, so the postal-address condition in section 12 does not gate it and we will not treat it as though it does. If a breach ever makes a better channel necessary, building one is part of the response, and we will say here what we built.
If you believe you have found a vulnerability, write to security@tacendum.com; hello@tacendum.com reaches the same people if you would rather use that. We will not pursue anyone for good-faith research that respects other people’s data and does not degrade the service.
Children
Tacendum is not intended for anyone under 18 — the Terms raised the minimum age from 13, deliberately: a service that cannot read what it carries cannot moderate it either. We do not knowingly collect personal information from anyone under that age. In Europe the age of independent consent is 16, or as low as 13 by country; our floor is higher than all of them. If you are under 18, please do not create an account.
There is no age check anywhere in the app, and there could not be a meaningful one: the data we hold for an account — an id, a creation time and a set of public keys — would not tell us how old anyone is. The only age signal is the rating on the App Store listing, a warning to the person installing it rather than a gate.
Between thirteen and eighteen — an age band the Terms no longer admit, and one we cannot detect — several state laws add duties for a service that knows a user is a minor: no targeted advertising, no sale of their data, no profiling toward decisions that matter. None of those things happens here, to anyone of any age.
If a child has an account
Write to hello@tacendum.com. United States law gives a parent the right to direct us to delete a child’s information, and we will honour that. Here is exactly how.
- What we hold, we will tell you. For any account it is the same short list: an account id, the time it was created, a set of public keys, possibly an Apple device token, which of your devices belong together and what kind each is, a keyed scrambling of any email address or username you linked with the time you verified it and your findability switch, and whatever messages are queued undelivered as ciphertext nobody can read. There is no message history, no profile, no contact list and no location on our servers to review (section 04).
- If you have the child’s phone, delete the account in the app. It takes under a minute, needs nothing from us, and does more than we can: it erases the device as well as the server. That is the remedy we would point any parent at first.
- If you cannot, we will delete it by hand. There is no administrative endpoint, but the accounts table is our own database and rows can be removed from it. On a parent’s request, we remove: the account row; the row claiming that identity key; any envelopes queued for the account; its one-time prekeys; its live-connection row; every session; and the push-token row holding the Apple device tokens. That is everything on our side tied to that account — the same set the app’s own deletion removes, matched since 4 August 2026 (section 20).
- What we cannot reach is the phone. Messages already delivered are on the device, and there has never been a way in from our side. If the phone is in front of you, delete the app; if it is not, nothing we do touches it.
- We act on a parent’s word, and that is deliberate. We cannot verify parentage — we hold nothing to check a claim against — and the children’s-privacy rule does not let our inability to verify erase your right: once you have told us an account is your under-13 child’s, we know it, and the duty to stop collecting and to delete attaches to that knowledge. So a good-faith request — tell us how you know the account is your child’s — is acted on. The stakes make that the right rule as well as the required one: everything a hand-deletion removes is an id, public keys, undelivered ciphertext and a push token, all of which one tap recreates — so a false request gains an impostor almost nothing, while refusing a true one would keep collecting from a child. We reserve refusal for a request showing affirmative signs of bad faith — this route being used to strip an account from someone the requester is targeting — and a refusal comes in writing, with the reason.
- You can refuse further collection. Collection only happens while an app is running with that key, so removing the account stops it. If we ever come to hold anything else tied to that account, the same request covers it.
- If you think we have handled this wrongly, the Federal Trade Commission is the venue, and you do not need our agreement to go there.
One more piece of exactness: if the children’s-privacy rules formally attach to us, the operator’s contact notice must carry a postal address and a telephone number as well as an email address. We do not publish a postal address today; the registered mailbox that section 12 contemplates before any email send is the same answer here, and this section would carry it.
Legal demands
The most useful thing a policy can say here is what actually exists to be handed over. If we were compelled by valid legal process, the most we could produce about an account is:
- the account id, the time the account was created, and the public keys on the row;
- the claim row linking that public identity key to that account;
- any messages still undelivered at that moment — sending account, receiving account, message id, timestamp, whether the message opened a new session, and ciphertext we cannot decrypt;
- whether a live connection existed, and when it began;
- the push-token row: the Apple device tokens, which Apple environment they belong to, and the app’s bundle id;
- rate-limit counters still inside their window, which can include a source IP address or a pair of account ids;
- attachment ciphertext still inside its thirty days, and storage access-log entries — which include the uploading device’s address alongside an object identifier;
- the relay’s own log on the relay host for up to seven days, which can contain client addresses. That log cannot be joined to an account by the relay or by anyone who takes it, because the salt lives elsewhere — but we hold the salt, so a demand that reached both could join them;
- any abuse report still inside its hundred and eighty days — the reporting account, the reported account, a category, and whatever message excerpts the reporter explicitly chose to attach, which are the one readable text in this list (section 04);
- log lines within the ninety-day window, which can carry an account id, an account class, a session count, an Apple environment and refusal reason, an upload size, or the raw text of an error from a cloud service;
- anything still inside the thirty-five-day backup window.
What we could not produce, because it does not exist here: the content of any message, photo, file, call, vault item or shared location — beyond the excerpts a reporter explicitly attached, named above; your conversation history; your contacts; your profile name or avatar; an email address or username in the clear; your call log; who you have blocked; or a list of everyone you have ever messaged. We keep no such history, and the content we do carry is unreadable to us. The next paragraph says what a scrambled identifier could still be tested against, because that is the honest limit.
On “a directory of our users”, be exact. No service we run can query or scan the accounts table, and the table has no index, so nothing in the running system can produce a list of users or answer “is this key registered” in bulk. The table is still our own database, and an operator with administrative credentials could read rows out of it by hand. So the honest answer to a demand for “all your users” is that no feature exists to answer it, and that what could be assembled by hand is a list of random ids, creation times, public keys and scrambled identifier rows — no names, and no address or username readable off the row. The limit of that scrambling, stated plainly: it is keyed by a secret we hold, so an operator with the secret, or anyone who compels one, could test a known email address or username against it. Nothing on the row says who talks to whom.
That is a statement about what we retain, not about what passes through us. As section 03 says, we see the sender, the recipient and the time of every message as it is relayed — and, for a room, who each copy of one message went to, which is how a room’s membership becomes visible without our holding a roster (section 05). Nothing accumulates any of it into a history, and a demand reaching backwards would find no such history to seize. A demand that reached forward in time would be a different question, because that information passes through our hands whether or not we write it down.
Separately, Apple holds its own records of the pushes we send to your device. A demand directed at Apple is not something we control or would be told about.
Our posture: we require valid legal process, we read it narrowly and push back where it reaches further than the law allows, and we will tell you a demand arrived unless we are legally prohibited from telling you. We cannot produce the contents of your messages or calls, because we never have them.
Changes to this policy
This page changes when the product changes, and the “last updated” date at the top changes with it. It is also re-read against the system at least once every twelve months and re-dated even if nothing changed. There are two kinds of change, handled differently on purpose.
- A correction — where this page described the system wrongly, as several paragraphs of this revision do — goes up immediately. Leaving a false statement in place for thirty days to be procedurally polite would be the worse choice, and each revision says plainly what was wrong.
- A material change — where we intend to start doing something new with your data — is posted here at least thirty days before it takes effect, with the future date it takes effect and a note saying what is changing. That lead time is the point: it is what gives you room to delete your account first if you would rather not be part of it.
A new policy does not reach backwards. Data we already hold stays governed by the policy in force when we collected it. If we ever want to use something already collected in a way this page does not permit, that needs your agreement, not a quiet edit. We should say what that would actually take, since we have no address to ask at: the agreement would have to be collected inside the app, and building that mechanism would be part of making such a change rather than an afterthought to it.
Continued use after a change is not us treating you as having agreed to it, because we cannot tell you that a change happened: we hold no name for you and no address we could write to, and we will not start using push for announcements without saying so here first. This page is the reliable place to see what we hold, and reading it occasionally is the only mechanism either of us has.
Corrections
The rule above says a correction goes up immediately. This is the list of record — what changed, and when. The body of this page states only the current truth and points here.
Corrected on this page, by the revision of 29 August 2026:
- This page said no email address, phone number or username exists in an account, and that no lookup of any kind exists. Since 29 August 2026 both are optional. An account still needs none of them. You may link an email address or claim a username, optionally and revocably, so that someone who already knows it can find you — only if you switch that on, per identifier. What we hold is a keyed scrambling, never the thing itself; section 02 and section 04 now describe the rows, the limits on searching, and what the scrambling does and does not buy. The sentence that denied any contact-discovery endpoint at all is retired.
- This page said there is no recovery of any kind. There is still none for messages or keys. A linked email can recover the account grouping and discoverability only, after a delay your other devices are told about; section 02 states the scope.
- Someone who finds you learns the shape of your devices. A lookup that resolves hands the finder the list of your account’s devices and what kind each is — the same thing anyone who already holds your id learns when they start a chat — because the first message must be encrypted to each device. This was true before this revision for anyone holding your id and is now reachable by identifier as well; section 02 says so where the lookup is described.
- A new processor. Verification and recovery codes by email go through Amazon SES — section 13.
Corrected on this page, by the revision of 19 August 2026 — and the first of these is the most serious correction this page has carried:
- This page said no call statistics leave your device. They do. Since 13 August 2026 a finished call sends us a short report — audio or video, one-to-one or room, answered, connected, how it ended, how long it took to connect, how long it lasted, and a room call’s peak size — with no account id on the figures and no way to switch it off. Two places said otherwise: section 06 stated it as a flat negative, and section 09 listed it under what we never collect. Both are rewritten, and section 06 now describes the report in full. It was written when it was true and was not revisited when the feature shipped, which is exactly the failure this list exists to record.
- The list of what deletion does not erase was missing two entries, and claimed to be complete. It now names the consent records other people wrote about your machines — the one residual on that list with no expiry of any kind — and the eight-day de-duplication row a call report leaves. Section 11.
- Consent records were not described anywhere, although they have existed since 15 August 2026. Section 04 now sets out what one holds, that nothing can list them, and that they do not expire.
- The attachment storage access log was given as ninety days in three places. It was shortened to thirty on 14 August 2026, matched to the attachment it describes — section 04, section 10, section 11.
- The description of deletion did not mention that an account owning adopted machines is refused until they are retired, or that activity rows and your own consent records go with the rest. Section 11.
- Section 04 opened by counting twelve kinds of request to our API. There are nineteen.
- This page said the complete corresponding source was published, tagged per release, with version 1.0 at /tree/v1.0. None of that was true. The repository is reserved and empty, no tag has ever been pushed to it, and that tag could not have existed even in principle — release tags are build-exact, so a bare v1.0 will never be a tag. The lede and section 17 now say the source is not published, that the written offer is the route until it is, and that the pointer to trust is the one the app carries rather than anything typed here.
Fixed in the product, 4 August 2026:
- The attachment access log now expires after ninety days, ahead of the 31 December 2026 commitment this page previously carried — section 04. (Shortened again to thirty days on 14 August 2026; see the 19 August entries above.)
- Deleting your account now deletes the push-token row; before then the row lapsed only on its own ninety-day expiry, so an Apple device token tied to your account id could outlive the account by up to three months. The app’s deletion and the exceptional hand-deletion have removed the same set since — sections 07, 11 and 18.
- The switch “Let Apple wake this iPhone” shipped; before then a VoIP token existed whether or not you agreed to notifications, with no way to decline it — section 07.
Corrected on this page, by the revision of 30 July 2026:
- It described the backup gap wrongly twice over: it said the SQLite journal file holds the newest messages, when it holds old copies of database pages being rewritten, and it implied the per-file exclusion flag would reach that file at the next launch, which the old design could not guarantee. The databases now live inside an excluded directory — section 08.
Corrected on this page, by the revision of 5 August 2026:
- This page said the relay host “never sees a packet” on a direct call. Wrong: address discovery and relaying are the same host, so it observes your phone’s public address on essentially every call. The sentence had been copied from a comment in our own source, which still says it — section 06.
- It said a room cannot ring; that stopped being true when small-group calls shipped. A room can carry a voice call of up to six — section 05.
- It said ordinary page reads matched no firewall rule and entered no request sample. Sampled requests, page reads included, carry a source IP address for a few hours — section 12.
- It rested the GDPR position on registration requiring a United States or Canadian phone number; that premise left with the phone number — section 14 carries the current reasoning.
- It committed to less breach notice than the law requires; section 17 now commits to email, a thirty-day website notice and statewide media together.
- It overstated “no administrative endpoint” as “we cannot switch an account off”; rows can be removed from our own database by hand — sections 09 and 18.
Contact
Privacy questions, rights requests, appeals and deletion requests go to hello@tacendum.com. Security reports and suspected vulnerabilities go to security@tacendum.com, or to the same hello address if you prefer. Both are read by a person.
Tacendum is operated by Mirana Technologies Inc.
See also the Terms of Service.