Contents

Learn · 4 of 10

Contacts and invites

A relationship starts from a card or an invite link and exists once both people approve it. Every contact goes through the same five states.

none pending_out pending_in active blocked I redeemed an invite /sent a request someone requested me they approve(contact_accepted call) I approve I reject I block I unblock remove_contact(either side)
Contact state on each side, from the specification’s own diagram (§ 5). Not drawn: a request that expires returns to none, and an outgoing request that is rejected moves to blocked.

Always mutual, always approved by a person

Contacts are always mutual and always human-approved; an invite’s auto_accept is the issuer pre-approving at share time (§ 5). Whichever way two people meet, what is pinned at the end is the same: the root fingerprint the card’s leaf names as its issuer, together with the endpoint the leaf names, and the leaf itself as the latest one seen. A card whose chain never validates is not a contact; it is a piece of paper (§ 5.2).

Two ways to meet

An invite is a short URL whose entire state lives with the issuer: its expiry, how many times it may be used, whether redeeming it creates the contact at once or lands as a request, the permission preset granted on accept, and a label. Because the state is server-side, all of it can be changed after the link is shared, and deleting the token invalidates the link with nothing cryptographic to chase. The URL carries no personal data and no key; it resolves to the issuer’s signed card and chain, so the redeemer holds the issuer’s card before redeeming and pins a root whose chain reached it over the address the issuer personally handed out (§ 4, § 5.1).

A card is a standard vCard 4.0 carrying the leaf certificate, shared over WhatsApp, email, AirDrop or as a QR: the channels people already use, so no new sharing channel is invented. An agent watching the phone book can offer “connect our agents?” for any contact that carries the PACT properties; that request always lands as a manual approval on the other side. Trust in the card equals trust in the channel that carried it, the same trust people already place in a shared phone number (§ 3, § 5.2).

What a stranger gets

A caller whose root resolves to no pin is a guest, with two tools: redeem_invite and request_contact (§ 6.1). Declining a request is a demotion, not a deletion: the requester moves to blocked, and their next request receives the same {"status": "pending"} any stranger gets while nothing is recorded and the owner is never bothered — blocked is indistinguishable from never-met (§ 5, § 12). Removing a contact notifies the peer and deletes the pin on both sides; blocking is local only, and no notification is sent.

A name is a claim, not an identity

The identity is the root’s fingerprint; the name beside it is whatever the card’s author typed. Two contacts may carry the same name, and a receiving implementation never treats the name as identifying: where two pinned contacts render alike, it shows the fingerprint alongside, and it lets the owner assign their own local name for a contact, which is the only name no peer can influence (§ 3).