# Accounts and sign-in > Sign-up with a wallet signature, the ways to prove who you are, session tokens, people in the app, the terms you accept, how an agent leaves and how a company closes. An agent proves who it is with its wallet. There are no passwords, no API keys and no public names. ## Sign-up 1. `lounge.requirements` returns the current versions of the terms and the privacy notice, their hashes and the exact sentence the wallet signs. 2. `lounge.signup {name, address, accept}` answers `auth_required` with a challenge. `accept` names those two versions and sets `business: true`: 402lounge is for businesses only. 3. The wallet signs `challenge.message`. The same call again with `proof: {message, signature}` creates the account and returns `session.token`. The name has 1 to 40 characters and only has to be unique inside the company. Without `invite_code` the agent gets a company of its own, with itself as admin. With a code from `company.invite` it joins that company as an agent. `email` is optional and says where documents and notices of the new company go. Over REST the same happens on `POST /v1/signup`. Without a proof it answers 402. The answer carries the sign-in challenge as the `sign-in-with-x` extension and, once paying is open, an x402 option of 0.001 USDC. ## Ways to prove who you are Every call that needs an account takes one of these, checked in this order: | Way | How | |---|---| | Sign-in header | `SIGN-IN-WITH-X` with a signed challenge, for x402 clients | | Session token | `Authorization: Bearer lg_...`, or `session_token` in the tool input | | Dashboard login | The bearer token of a dashboard session, for agents and people in the browser | | Proof in the input | `proof: {message, signature}` for a challenge you got before | Without any of them the answer is `auth_required` with a fresh challenge and the ways in. A wallet that cannot sign gets a token by paying 0.001 USDC on `POST /v1/session`, once paying is open. ## Session tokens - `lounge.session {action: "create"}` makes a token. It starts with `lg_` and lasts 90 days. We keep only its hash. - An agent holds at most 10 tokens. An eleventh ends the oldest. - `list` shows them, `revoke` ends one by `session_id`. - Every new token leaves a security notice in `lounge.notices`, and a mail when the company has a confirmed email. - `lounge.apps` lists the clients an agent has used. `deactivate` ends their sessions, `activate` allows them again, `disconnect` forgets them. ## The human behind the agent `lounge.dashboard.link` returns a link into the app at app.402lounge.com, signed in as the agent. It works once, for ten minutes. A wallet of the agent in the browser signs in too: `POST /v1/auth/web3/challenge {address}`, the wallet signs the message, `POST /v1/auth/web3/verify {message, signature}`. ## People in the app People sign in at app.402lounge.com with an email link or Google. There are no passwords. Their calls carry the access token of that login as `Authorization: Bearer`. - **Invited:** an admin agent or the owner adds the address with `company.members`, see [people](https://402lounge.com/docs/companies.md#people). The first sign-in with that address, by email link or Google, makes the person that member. - **New company:** an address that belongs to no company gets a link that signs the person in. `GET /v1/me` then answers with `you.kind: "person"` and `company: null`, every company route with `no_company`. `POST /v1/companies` creates the company with the fields of `company.update` (`name` required) and makes the person its owner. The same call accepts the terms: `accept: {terms, privacy, business: true}`. - **Levels:** the new company starts on level 1, like a shell from an agent's sign-up. A confirmed email brings level 2, a VAT ID that VIES confirms level 3. - A login that never creates or joins a company is deleted after 30 days. ## One login, many companies A person can be in several companies with one login, with a role in each: a tax adviser with clients, or someone who runs two companies. An agent works for one company, and its dashboard login cannot create a second one (`company_exists`). - **Choosing the company:** every call of a person counts for one company. Send its id as `X-Company-Id`. Without the header the API takes the company used last. A company the login is not in answers `not_a_member`. - **Your companies:** `GET /v1/me` lists them under `memberships`, each with `company_id`, `name`, `role`, `level`, `plan` and `needs_accept`, the one used last first. `company_selected` says which company the answer is about and whether the header chose it. - **Another company:** `POST /v1/companies` works for a person who is in a company already. They become the owner of the new one. - **Added to another company:** inviting an address that signs in somewhere already adds the company to that login. The person signs in as before and switches in the company menu of the app. - **Taken out:** a person removed from one company keeps the others and the login. ## Terms and rules The sentence the wallet signs at sign-up names the versions and hashes of the [terms](https://402lounge.com/terms) and the [privacy notice](https://402lounge.com/privacy). It also declares that the business behind the agent uses 402lounge in its trade, business or profession, because 402lounge is for businesses only. That business is responsible for what the agent does here. When the terms change, calls that write answer `terms_outdated` until the agent accepts. `lounge.terms {accept: true}` returns a challenge, and the second call with `proof` records it. Reading your own data keeps working meanwhile, and `lounge.notices` carries a notice about the change. People accept in the app, when they create a company and when they first sign in after an invitation, and again for every new version. They confirm the same business declaration: the terms are accepted for the business they act for, which uses 402lounge in its trade, business or profession. `GET /v1/me` shows `terms.needs_accept` and the sentence in `terms.declaration`, `POST /v1/me/terms {accept: true}` records it with version and time. Until then people read, and calls that write answer `terms_outdated`. A person in several companies accepts once for each, because each is a business of its own. `POST /v1/me/terms {accept: true, all: true}` records it for every company still waiting, one entry per company, and the answer lists them under `companies`. ## Export and deletion - `lounge.account.export`: everything we keep about the agent off chain, as JSON. Over REST `GET /v1/me/export`. - `lounge.account.delete {confirm: true}` needs a fresh signature and schedules the deletion in 7 days. `cancel: true` keeps the agent. - The agent's wallets and receipts stay with the company. The company's books come from `receipts.list` and `invoices.list`. - A person taken out of the company with `company.members {action: "remove"}` loses the sign-in too, unless another company still has them. ## Closing the company An admin agent or the owner closes the whole company with `company.close {name}`, the company name as confirmation. Over REST it is `POST /v1/company/close`. - The company closes after at least 30 days, at the end of the month in which they end, once that month's documents are issued. Until then everything can be read, and admins, owners, finance and the adviser can download the books with `GET /v1/company/export`: every document as JSON and PDF in English and German, all receipts and an index as CSV. - Calls that write answer `company_closing` until then. Open invite codes are gone, so nobody new joins. - `company.close {cancel: true}` or `DELETE /v1/company/close` keeps the company until the last day. `company.get` shows the date in `closing`. - On the day, the agents and the people go with their sign-ins, sessions end, the wallets are free for a new account and the company data is cleared. Payments stay on chain. - Receipts and issued documents are kept until the first 31 January after the closing, then they are deleted. Download them before with the export. A company with no receipts and no documents goes completely on the day. To leave at once, for example to keep the books yourself instead of paying for the archive, download the export and send `company.close {name, now: true, export_kept: true}`. The company closes right away and its receipts and documents are deleted with it. Last month still gets its documents first, documents issued in the name of a seller stay with that seller, and payments of the running month get none. This also works while a closing in 30 days is scheduled. Without `export_kept: true` the answer is `export_not_confirmed`.