# 402lounge docs > Receipts, monthly vouchers and a register for AI agents that pay with x402, in USDC on Base. 402lounge reads the chain and writes the paperwork. It never holds keys or money and is never in the payment. Every page of https://402lounge.com/docs and every tool of the MCP server in one file, for agents and language models. The index is https://402lounge.com/llms.txt. MCP: https://mcp.402lounge.com/mcp. REST: https://api.402lounge.com/v1. # Docs Source: https://402lounge.com/docs > How 402lounge fits around an x402 payment, and where to start if you run an agent, keep the books or sell a service. 402lounge sits next to x402 payments, not inside them. Your agent pays sellers from its own wallet, as it does today. We read the transfer on Base and write the paperwork: a receipt for every payment, one voucher per seller each month, and a register that says who is behind a payTo wallet. ## How the pieces fit 1. Your agent connects to the MCP server and signs up with its wallet. The account is a company from the first call. 2. Before it pays a seller for the first time, it asks [the register](https://402lounge.com/docs/register.md) who owns the payTo address. 3. It pays over x402, directly. Nothing about the payment changes. 4. It reports the payment with `receipts.record`. Payments from the company's wallets become receipts even when nobody reports them. A report adds what was bought. 5. Once the company data is in, the company gets one voucher per seller for every month. ## Where to start - **You build or run an agent:** [Quickstart](https://402lounge.com/docs/quickstart.md), then [Wallets](https://402lounge.com/docs/wallets.md) and [Receipts](https://402lounge.com/docs/receipts.md). - **You keep the books for a company:** [Companies, agents and people](https://402lounge.com/docs/companies.md), then [Monthly vouchers](https://402lounge.com/docs/vouchers.md). - **You sell an x402 service:** [For sellers](https://402lounge.com/docs/sellers.md) and [what the levels mean](https://402lounge.com/levels). - **You want every detail:** [MCP tools](https://402lounge.com/docs/tools.md), [REST API](https://402lounge.com/docs/api.md) and [Errors and limits](https://402lounge.com/docs/errors.md). ## Endpoints | What | Where | |---|---| | MCP server | `https://mcp.402lounge.com/mcp`, Streamable HTTP, no key to connect | | REST API | `https://api.402lounge.com/v1`, the same functions as the tools | | Network | USDC on Base. Receipts and vouchers cover Base only | ## For agents Every page here exists as plain Markdown too. Agents read that faster than this page. - [llms.txt](https://402lounge.com/llms.txt): the index, with a link to every page as Markdown - [llms-full.txt](https://402lounge.com/llms-full.txt): every page and every tool in one file - [skill.md](https://api.402lounge.com/skill.md): sign-up and the first receipt as a skill file - [.well-known/x402](https://api.402lounge.com/.well-known/x402): what is free and what costs 0.001 USDC, for x402 clients ## What it costs Everything an agent does here is free: the account, wallets, register lookups, receipts and reports. A wallet that cannot sign a message proves itself with 0.001 USDC instead, once paying is open. `lounge.requirements` says whether it is (`payments_open`). Plans for companies are on [Pricing](https://402lounge.com/pricing). # Quickstart Source: https://402lounge.com/docs/quickstart > Connect your agent, let it sign up with its wallet and turn its next x402 payment into a receipt. You need an MCP client and a wallet on Base that can sign messages. The agent does every step itself. You only add the server. ## 1. Add the MCP server In Claude Code, run this once in a terminal: ``` claude mcp add --transport http 402lounge https://mcp.402lounge.com/mcp ``` Clients that read a JSON file take the same URL: ``` { "mcpServers": { "402lounge": { "url": "https://mcp.402lounge.com/mcp" } } } ``` Cursor, OpenClaw, Hermes, Grok and others are on the [MCP page](https://402lounge.com/mcp), each with its exact setup. ## 2. Let the agent sign up Tell it "sign up at 402lounge". It calls `lounge.requirements` for the current versions of the terms, then `lounge.signup` twice: ``` lounge.signup { name: "Research", address: "0x4b7e1d2c90a6f3e58d1c7b20e9a4f6d3c8b51e07", accept: { terms: "", privacy: "", business: true } } ``` The first call answers `auth_required` with a challenge. The wallet signs `challenge.message`, and the same call with `proof: {message, signature}` creates the account. The answer carries a session token. The agent keeps it and sends it as `Authorization: Bearer lg_...` from then on. The account is a company from this moment, named after the agent. [Accounts and sign-in](https://402lounge.com/docs/accounts.md) has the details. ## 3. Pay as usual, then report it Your agent pays a seller over x402 exactly as before. The seller's answer carries the `PAYMENT-RESPONSE` header with the transaction hash. Right after, the agent calls: ``` receipts.record { tx_hash: "0xbcbca5c39efb57034965b0e84225f6264840c0c940f58e0980844a2bc888da4c", resource_url: "https://api.northpine.example/metrics/v2/projects", amount: "0.15" } ``` The answer says `pending` until Base confirms the transfer. ## 4. See the receipt The indexer reads Base every minute and waits for 12 confirmations. Then `receipts.list` shows the receipt: the seller from the register, what was bought, the agent that paid and a EUR value at the ECB rate of the day, marked provisional. `lounge.dashboard.link` gives the human behind the agent a browser link into the dashboard, valid for ten minutes. ## 5. Add the company data Receipts work without it. For one voucher per seller every month, an admin agent calls `company.update` with the legal name, address, country and email, plus a VAT id if the company has one. [Companies, agents and people](https://402lounge.com/docs/companies.md) says what each field does. # Wallets Source: https://402lounge.com/docs/wallets > Which wallets work, how a wallet proves it is yours, and how a company holds several of them. 402lounge never creates, holds or asks for keys, and it is never in the payment. A wallet proves once that it is yours. After that we only read its USDC transfers on Base. ## Which wallets work Any wallet on Base that can pay x402 in USDC: a viem key, Coinbase CDP, thirdweb, Privy or a Safe. To sign up for free it also has to sign a message (EIP-191 `personal_sign`). Plain keys and smart accounts both work. We check smart account signatures with EIP-1271 and EIP-6492. Coinbase Agentic Wallet cannot sign messages today. It proves itself with 0.001 USDC instead, as long as paying is open (`payments_open` in `lounge.requirements`). Its setup: ``` npx skills add coinbase/agentic-wallet-skills npx awal auth login npx awal auth verify npx awal address ``` The last line prints the address the agent signs up with. Fund it with USDC on Base. ## How a wallet proves itself - **Signature, free.** `lounge.signup` and `lounge.wallet.add` answer with a challenge: an EIP-4361 message for 402lounge with a nonce that works once, for five minutes. The wallet signs it, and the second call carries it as `proof` (or `wallet_proof` when you add a wallet). - **Payment, 0.001 USDC.** `POST /v1/signup`, `POST /v1/session` and `POST /v1/wallets` answer 402 with an x402 payment option next to the challenge. Paying it from the wallet is the proof: the payment goes to our wallet on Base, and we keep its transaction with the proof. If the facilitator does not answer, the 402 offers only the signature for that moment. Paying 402lounge for a plan in USDC is something else: [Paying 402lounge](https://402lounge.com/docs/billing.md). ## Several wallets in one company Wallets belong to the company. An agent operates the wallets assigned to it. - `lounge.wallet.add {address}`: the new wallet signs its own challenge. How many follows the plan: Free 1, Books 5 per agent and 15 in all, Books for teams without limit ([plans and their limits](https://402lounge.com/docs/errors.md#plans-and-their-limits)). - `lounge.wallet.list`: every wallet of the company with the agent that runs it. `mine: true` lists only yours. - `lounge.wallet.primary`: the wallet you sign in with. - `lounge.wallet.remove`: never your last wallet and never the one you sign in with. Sessions made with it end, its receipts stay. - `company.wallet.assign`: an admin moves a wallet to another agent, or leaves it unassigned. Receipts already written keep the agent that paid. - `company.wallet.label`: a name for your own lists, like "Research budget". A wallet belongs to one company only. Adding it a second time answers `wallet_taken`. ## Networks We read USDC on Base (chain 8453). Payments on other networks do not become receipts, even from the same address. # Accounts and sign-in Source: https://402lounge.com/docs/accounts > 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`. # Receipts Source: https://402lounge.com/docs/receipts > One receipt for every outgoing USDC transfer of a company wallet, with the seller, what was bought, the agent that paid and a EUR value. The chain says how much was paid and to which address. A receipt adds who is behind that address, what was bought, which agent paid and what it was worth in EUR. ## What becomes a receipt Every outgoing USDC transfer on Base from a confirmed wallet of the company, reported or not. The receipt belongs to the company and names the agent that operated the wallet when it paid. Payments from wallets we do not know, and payments on other networks, do not become receipts. ## Report what you bought Call `receipts.record` right after every x402 payment. Only `tx_hash` is required, the rest makes the receipt better. | Field | What to send | |---|---| | `tx_hash` | The settlement transaction from the `PAYMENT-RESPONSE` header (base64 JSON, field `transaction`) | | `resource_url` | The URL you paid for, starting with `https://` | | `amount` | What you paid in USDC, like `"0.002"`, up to six places | | `description` | What you bought, in your words, up to 280 characters. The seller's catalogue wins when it knows the URL | | `pay_to` | The payTo address from the payment requirements | | `payment_response` | The raw `PAYMENT-RESPONSE` header, if you still have it | Over REST it is `POST /v1/receipts` with the same fields. A company reports a transaction once. A second report answers `report_duplicate`. ## From report to receipt | State | Meaning | |---|---| | `pending` | Not on our side of the chain yet. The indexer reads Base every minute and waits for 12 confirmations | | `confirmed` | Matched with the transfer, the receipt is written | | `mismatch` | The reported amount differs from the transfer. The receipt shows the amount on chain | | `not_found` | Two days passed and the chain never showed the transfer | ## The seller on a receipt We look up the payTo address in [the register](https://402lounge.com/docs/register.md): - `verified`: the wallet proved it belongs to the listing (level 1). The receipt names the seller. - `listed`: a listing names the wallet, but the wallet has not proved it (level 0). - `unverified`: no listing claims the wallet. The receipt has no seller name and no input VAT. ## The EUR value Each receipt carries the ECB reference rate of the payment day, or of the business day before when the ECB publishes none, and the EUR amount at that rate. It is always marked `provisional` until your tax adviser confirms the method. Until the rate is out, the receipt says `no rate yet` and gets it later by itself. ## Read the receipts - `receipts.list {month: "2026-10"}`: one month, newest first, with totals per seller and per agent and the reports still waiting. `mine`, `agent_id`, `wallet` and `status` narrow it, `limit` (up to 200) and `before` page through it. Months start at midnight Europe/Berlin, the same months as the vouchers. - `receipts.get {id}`: one receipt by id or transaction hash. - Over REST: `GET /v1/receipts?month=2026-10` and `GET /v1/receipts/{id}`. ## One receipt An example with made-up data. Amounts in USDC have six places, in EUR two. ``` { "schema": "402lounge-receipt/0.1", "id": 92097, "network": "base", "tx_hash": "0xbcbca5c39efb57034965b0e84225f6264840c0c940f58e0980844a2bc888da4c", "block_time": "2026-10-31T01:41:09.444Z", "payer": "0xc2a9e61f4d07b83e5a2c19d6f0e7b4a38d5c9e12", "operator": { "agent_id": "example-agent-research", "name": "Research" }, "pay_to": "0x6e2d4a9b17c3f08e5d21a7c46b9f3e0d82a5c71b", "amount": { "usdc": "0.150000", "eur": "0.14", "fx": { "rate": "1.0930", "day": "2026-10-30", "source": "ecb", "note": "previous business day", "provisional": true } }, "seller": { "status": "verified", "level": 1, "listing": { "slug": "northpine", "name": "Northpine Data", "maker": "Northpine Data Inc." }, "legal_entity": null }, "item": { "resource_url": "https://api.northpine.example/metrics/v2/projects", "description": "Projects", "source": "catalog" }, "provenance": { "money": "chain", "item": "catalog", "report_id": null }, "links": { "tx": "https://basescan.org/tx/0xbcbca5c39efb57034965b0e84225f6264840c0c940f58e0980844a2bc888da4c", "register": "https://api.402lounge.com/v1/register/0x6e2d4a9b17c3f08e5d21a7c46b9f3e0d82a5c71b" } } ``` `provenance` says where each part comes from: the money always from the chain, the item from the seller's catalogue, the agent's report or nowhere. # The register Source: https://402lounge.com/docs/register > Wallet in, seller out. Who owns a payTo address, on which level, and what the service sells. A payTo address says where the money goes, not to whom. The register connects addresses to listings and says how well that link is proven. Looking up is free and needs no account. ## Look up a wallet ``` register.lookup { address: "0x6e2d4a9b17c3f08e5d21a7c46b9f3e0d82a5c71b" } ``` Over REST: `GET /v1/register/{address}`. People use the [register page](https://402lounge.com/register), and `/register/
` opens it with the answer. Lookups are limited to 120 a minute per IP address. ## What comes back | Field | Meaning | |---|---| | `status` | `verified`, `listed` or `unverified` | | `level` | 1 for verified, 0 for listed, `null` for an unknown wallet | | `listing` | Name, maker, summary, endpoint, website and the directory page of the listing that owns the wallet | | `legal_entity` | The company behind the listing. Stays `null` until level 2 opens | | `endpoints` | The paid endpoints we know from the seller's 402 answers, with price and payTo | | `last_check` | Result and time of the last nightly 402 check | | `note` | One sentence on what the level means for your receipt | An example with made-up data: ``` { "address": "0x6e2d4a9b17c3f08e5d21a7c46b9f3e0d82a5c71b", "network": "base", "status": "verified", "level": 1, "listing": { "slug": "northpine", "name": "Northpine Data", "maker": "Northpine Data Inc.", "endpoint_url": "https://api.northpine.example/metrics/v2/projects", "directory_url": "https://402lounge.com/directory/northpine", "verified_since": "2026-10-12T09:30:00.000Z" }, "legal_entity": null, "endpoints": [ { "method": "GET", "url": "https://api.northpine.example/metrics/v2/projects", "description": "Projects", "price_usdc": "0.15", "source": "probe" } ], "last_check": { "ok": true, "checked_at": "2026-10-31T03:15:40.000Z", "http_status": 402 }, "note": "Level 1: the wallet proved it belongs to this listing. The legal entity behind it is not verified yet, so a receipt is possible, an invoice is not." } ``` ## The levels | Level | Name | What is proven | |---|---|---| | 0 | Listed | A listing names the wallet, nobody proved it | | 1 | Wallet verified | The wallet signed for us or sent 0.01 USDC from itself | | 2 | Company checked | Legal entity, address, register entry and VAT id. Coming | | 3 | Invoicing | The seller lets 402lounge issue invoices in its name. Not open yet | A level says how much we know about who is behind a wallet. It is not a rating and not a recommendation. [What the levels mean](https://402lounge.com/levels) has the long version. ## The directory The directory lists the services the register knows, free and without an account. ``` directory.search { q: "on-chain data", filter: "verified", sort: "level" } ``` Over REST: `GET /v1/listings?q=&filter=all|verified|mcp&sort=level|new|name&limit=&offset=`. Each card has the name, host, summary, logo, the level with the date it was reached (`level_since`) and what the service publishes (`has`: MCP, `.well-known/x402`, `llms.txt`). `directory.get {slug}` or `GET /v1/listings/{slug}` adds the wallets with network and level, what each call costs, other networks the 402 answers offer (shown, not booked) and the links. Company and location show from level 2 on. One sponsored place can be booked. It comes first in `sponsored`, marked `sponsored: true` with the label "Sponsored", on the first page and only where it matches the search. It never changes the order of the results or a level. ## Before you pay someone new Call `register.lookup` with the payTo address of the payment requirements before the first payment to a new seller. What you do with the answer is your agent's rule, not ours. Some agents only pay `verified` wallets, some pay anyone and keep the answer with the receipt. # Companies, agents and people Source: https://402lounge.com/docs/companies > Every account is a company. How it gets its legal data, more agents and the people who read the books. The company is the root of everything. It owns the wallets, the receipts and the documents. Agents pay, people read and manage. ## Every account is a company Sign-up makes a company named after the first agent, with that agent as its admin. It starts on level 1 and already gets receipts. The legal data brings it up the ladder: | Level | Tier | What it needs | What it gets | |---|---|---|---| | 1 | `account` | A wallet that signed | Receipts for every payment | | 2 | `company` | `name`, `address_line1`, `postal_code`, `city`, `country` and a confirmed `email` | One document per seller and month | | 3 | `invoice_ready` | A VAT id that VIES confirms, address complete | Documents may name the company as the buyer | `company.get` shows the data, the level and `missing_for_company`, the fields still missing for the next step. `email_confirmed` in that list means the address is there and waits for its code. ## The company data An admin agent calls `company.update` with any part of the data. The answer lists what is still missing. | Field | What it is | |---|---| | `name`, `legal_form` | Legal name without the legal form, and the form, like `GmbH`. A form typed at the end of the name is taken off it | | `address_line1`, `address_line2`, `postal_code`, `city` | The registered address | | `country` | The ISO 3166 code, like `DE`. Documents with a tax note go to companies in Germany for now | | `vat_id` | In the format of its country, like `DE123456789`, `ATU12345678` or `EL123456789` for Greece, spaces and dots are taken out. Numbers of EU states are checked against VIES at once, `company.vat_check` asks again. Other numbers are kept as entered. `GET /v1/countries` has the format of every country | | `tax_number` | The tax number, where you have one | | `vat_status` | How the company stands with VAT: `vat_id` (registered with a VAT id), `tax_number` (registered, the VAT id is still to come), `small_business` (§ 19 UStG) or `exempt` (only VAT-exempt sales). or `not_registered` (no VAT registration, for example in the USA). Which of them fit depends on the country, see `GET /v1/countries`. It decides the tax note on the monthly vouchers, see [Monthly documents](https://402lounge.com/docs/vouchers.md) | | `email` | Where documents and notices go. A six digit code confirms it | | `skr` | `SKR03` or `SKR04`, the chart of accounts for exports, or `OWN` for any other chart in any country | | `own_accounts` | With `skr: "OWN"`: `{expense, clearing, usdc}`, the three accounts the DATEV batch books to, 4 to 8 digits each | | `currency` | The currency the app and the API show amounts in next to USDC, `EUR` by default. `USD` is the USDC amount itself, every other currency from `GET /v1/currencies` uses the ECB rate of the payment day. Receipts then carry `amount.local` and the totals `total_local`. Documents stay in euros | | `fx_method` | `ecb_daily`, the ECB reference rate of the payment day. Other methods come once they are built and a tax adviser has confirmed them | The email: `company.email {action: "start", email}` mails the code, `company.email {action: "confirm", code}` checks it. The code works for 15 minutes and five tries. A company on level 2 that changes its address keeps the confirmed one in use until the new one is confirmed, so its level does not drop. The VAT id: VIES is asked again at night when it could not answer, and once a month for every id. A change of level comes as a notice. ## More agents - `company.invite` gives a code that works for seven days. - A new agent signs up with `lounge.signup {invite_code}` and joins as an agent. - An agent with its own account calls `company.join {code}`. Its wallets, receipts and reports move into the company, and its own account goes away. That works while its account has no company data, no vouchers and no other agents. - `company.agents` lists every agent with its role, its wallets and what it paid this month. - `company.agent.update` renames an agent or changes its role. `company.agent.remove` schedules its deletion in 7 days, its wallets and receipts stay. ## People People sign in at app.402lounge.com with an email link or Google, and accept the terms there on their first visit. `company.members {action: "invite", email, role}` adds someone, `role` changes the role, `remove` takes someone out. A company always keeps an admin agent or an owner. A person can also start a company without an agent, see [people in the app](https://402lounge.com/docs/accounts.md#people-in-the-app). One login can be in several companies, see [one login, many companies](https://402lounge.com/docs/accounts.md#one-login-many-companies). ## Who may do what | Role | Who | May | |---|---|---| | `admin` | Agent | Pay and report, plus company data, agents, wallets and people | | `agent` | Agent | Pay, report, read the company's books, manage its own wallets and sessions | | `owner` | Person | Company data, agents, wallets and people, from the dashboard | | `finance` | Person | Read everything, issue and cancel documents, run the VAT check, choose the plan | | `adviser` | Person | Read everything and download the export, CSV and DATEV. Changes nothing. For the tax adviser | | `viewer` | Person | Read | Only agents pay and report payments. People read and manage. A call outside your role answers `not_allowed` with `your_role`. Who sees the list of people: admin agents, owners and roles that read people see everybody. Everybody else sees only themselves. Anybody can leave a company with `DELETE /v1/company/members/{id}` on their own id, except its last owner. ## Own roles The owner or an admin agent makes roles with their own name, for example "Agents only" for someone who looks after the agents and nothing else. A role sets one level per area: | Area | Covers | |---|---| | `receipts` | Receipts, documents, the month export. Levels `none`, `read`, `export`, `write` | | `company` | Company data, the company email and the logo | | `people` | The people of the company | | `agents` | Agents, their wallets and their session tokens | | `selling` | Listings, the sponsored place, seller documents | | `billing` | The plan, the archive and invoices from 402lounge | The other areas know `none`, `read` and `write`. `POST /v1/company/roles {name, areas}` makes one, `PATCH /v1/company/roles/{id}` changes it, `DELETE` removes one nobody has. Give it with `role: "custom"` and `custom_role_id` when you add a person or change their role. A role that changes people hands out only `viewer` and `adviser`, so nobody gives more than the owner gave them. Closing the company and making roles stay with the owner and admin agents. The database follows the same areas, so a role without receipts reads none of them with its login either. An area outside the role answers `not_allowed` with `area`. ## Board The board is where the people and agents of a company ask each other things, instead of by email: the tax adviser asks for a missing invoice, the agent answers that it is on its way, somebody marks it done. In the app it is "Needs a human" on the overview and the inbox. Agents use `company.requests`, the API is under [board](https://402lounge.com/docs/api.md#board). - Whoever reads the receipts reads and writes the board. A request can name a month of the books. - A new request mails the company email and everybody whose role exports or changes receipts: owners, finance, the adviser, own roles with it. Not the one who asked. - An answer mails everybody in the thread. When the one who asked follows up, the people who keep the books get it too. An answer opens a done request again. - Who asked takes a request back, the owner and admin agents delete any. Closing the company clears the board. ## Session tokens `GET /v1/company/sessions` lists the open session tokens of every agent: the client that holds it, the wallet, when it was made and when it ends. Whoever sees agents sees the list, the token itself never. An agent ends its own with `DELETE /v1/company/agents/{id}/sessions`, the owner, admin agents and roles that change agents end anybody's. Add `/{session_id}` to end just one. # Monthly documents Source: https://402lounge.com/docs/vouchers > One document per seller and month for every company with its data in. The overview on Free, the voucher with the tax note on Books. Numbered, chained and never changed. Hundreds of small payments to one seller make one document a month. Usually it is our record for the buyer: who was paid, for what, how much in USDC and EUR, not an invoice of the seller. Where the seller is on level 3 or agreed to self-billing, the month gets an invoice in the seller's name or a credit note instead, see [Invoices and credit notes](#invoices-and-credit-notes). ## Overview or voucher The plan decides which document a month gets. | Plan | Document | Number | What it adds | |---|---|---|---| | Free | Monthly overview | `U-…` | Lines, totals, rates and every payment. No tax note, not a voucher for bookkeeping | | Books and up | Voucher (Eigenbeleg) | `B-…` | The same, plus why it is a voucher and the tax note for your company | A paid plan counts for every month it ran into. Upgrade later and a month that already has an overview can be cancelled and issued again as a voucher. ## Invoices and credit notes Three ways lead to a month's document, the run takes the best one the seller allows: | Way | When | Document | Number | |---|---|---|---| | A, mandate | The seller's listing is on level 2, it signed the invoicing mandate and has Books | Invoice in the seller's name, issued by 402lounge | `L-…` | | B, self-billing | The listing is on level 2 and the seller agreed to self-billing | Credit note (Gutschrift) of the buyer, prepared by 402lounge | `G-…` | | C | Otherwise | Voucher or overview, as below | `B-…`, `U-…` | A and B need a buyer on level 3 (VAT ID confirmed by VIES) in the EU with Books or Books for teams, and payments to wallets of the listing that proved themselves. The tax case follows the seller and the buyer: | Seller | `tax_case` | On the document | |---|---|---| | Germany, charges VAT, buyer in Germany | `domestic_19` | 19 % VAT, worked out of what was paid | | Germany, small business, buyer in Germany | `domestic_small_business` | No VAT, with the note on § 19 UStG | | In the EU, buyer in another state | `eu_reverse_charge` | No VAT, both VAT IDs, "Reverse charge" with the term of the state whose rules apply | | Outside the EU, buyer in the EU | `third_country_reverse_charge` | No VAT, the seller's tax id, the same mention | Whose invoicing rules apply follows Art. 219a of the VAT Directive: the seller's state for an invoice with a mandate and an EU seller, the buyer's state for a seller outside the EU and for every credit note. The document names that state. The buyer's state is where the VAT is owed (Art. 196), and § 13b UStG appears only when the buyer is in Germany. A seller and a buyer in the same state outside Germany get the voucher, that case is not built yet. Credit notes go to buyers in twenty states, not yet to Italy, Hungary, Poland, Romania, Greece, Croatia and Portugal. A month up to 250 € gross for a German seller and a German buyer is a small amount invoice (§ 33 UStDV) and says so. Every invoice and credit note has its e-invoice under EN 16931 (UN/CEFACT CII D16B): `GET /v1/invoices/{id}/xml`. It lies in the archive next to the JSON and the PDFs, in the ZIP export, and the month CSV names it in the column `einvoice`. A document whose e-invoice does not pass our check is not issued. The seller sees every invoice in its name with `seller.invoices`, and its documents carry a second chain, `seller_prev_sha256`, from one invoice of the seller to the next. Cancel an invoice or credit note like any document. Its cancellation (`S-…`) is in the seller's range and its e-invoice is a credit note that names the original. The month is then issued again. A late payment gets a supplement in the way that applies at that time. ## The tax note The voucher picks its note from the company's country and `vat_status` (see [Companies](https://402lounge.com/docs/companies.md)). Tax notes are written for companies in Germany. | Company | `tax_case` | What the note says | |---|---|---| | Germany, `vat_id` or `tax_number` | `rc_13b` | The buyer owes the VAT under § 13b UStG and deducts it where entitled | | Germany, `small_business` | `rc_13b_small_business` | The buyer owes the VAT under § 13b UStG and cannot deduct it | | Germany, `exempt` | `rc_13b_exempt` | The buyer owes the VAT and deducts it only as far as its sales allow | | Germany, no status | `rc_13b_status_missing` | The status is missing and the deduction depends on it | | Outside Germany | `not_germany` | No tax assessment, only the payments and the EUR values | Every note also says what changes if the seller turns out to be established in Germany, and that EUR values are provisional until the tax adviser confirms them. This is not tax advice. Your tax adviser decides how you book it. ## When documents are issued Every night at 03:15 UTC the run looks at last month (Europe/Berlin) and issues documents for every company on level 2 or 3 that has payments no document lists yet. The first night after a month issues it. A company whose agents reported payments the chain has not shown yet waits one more night. Companies on level 1 keep their receipts but get no documents, because a document names the buyer with its address and a confirmed email. An admin, owner or finance can issue any finished month with `invoices.issue {month: "2026-10"}`. Receipts that still lack a EUR rate are skipped and listed in the answer. A month with more transactions than the plan covers is skipped with `month_locked` until the plan fits, see [plans and their limits](https://402lounge.com/docs/errors.md#plans-and-their-limits). ## The month so far `invoices.draft {month?}` shows what the run would issue today, one draft per seller, with lines, totals and the tax case. Nothing is stored and there is no number. Without `month` it shows the current month. Each draft has a PDF at `GET /v1/invoices/draft/pdf?month=2026-11&seller=`. ## Cancel and issue again A document is never changed. If one is wrong, an admin, owner or finance cancels it with `invoices.cancel {id, reason}`. That issues a cancellation (`S-…`) that names the original with its sha256 and shows its amounts with a minus sign. The original keeps its number and turns to `cancelled`. Its payments are open again, so `invoices.issue` for that month, or the nightly run for last month, puts them in a new document with the current data. ## Late payments Payments that arrive after a month was issued get a supplement: a document of the same kind for only the new payments, pointing to the month's first document with `supplement_of`. The first document stays valid. ## What a voucher holds - The buyer with its address and VAT id, and the seller as the register knows it - One line per endpoint: what was bought, how many calls, USDC and EUR - Every receipt behind the lines, with its transaction hash - The conversion method and the note that EUR values are provisional - The tax note for the company, as above ## How long we keep them As long as your company has a paid plan or the archive (5 € a month or 50 € a year, [Paying 402lounge](https://402lounge.com/docs/billing.md#the-archive)), its receipts and documents stay. Without either, the receipts and documents of a year are deleted on 31 January of the next year, so December still gets its documents and there is a month to download them. When a paid plan or the archive ends, at least 30 days pass before anything is deleted, and a notice comes on 1 December and on 15 January. Invoices and credit notes in a seller's name are the seller's records too: while the seller keeps its own, they stay for the seller when yours go, and you no longer see them. `company.get` shows the next date in `retention`. Your company keeps its own duty to retain its records, eight years in Germany and up to eleven years elsewhere in the EU, so download them with `GET /v1/company/export`, book the archive or keep a paid plan. ## Numbers and integrity Every document has a number like `B-2610-10427-01`: a letter for the kind (B voucher, U overview, S cancellation, L invoice in the seller's name, G credit note), year and month, the seller's own number, and the count of that seller's documents of this kind in the month, nearly always 01. Every seller keeps its number, 4 or 5 digits, a wallet no listing claims gets one too. The numbers run per issuer: the buyer's vouchers, overviews and credit notes in its own range, invoices in the seller's range. Documents issued before 3 November 2026 keep their old numbers like `402B-northpine-2026-000017`. A document carries the logo of whoever issues it, as it was on that day: the buyer's on vouchers, overviews and credit notes, the seller's on invoices in its name. Upload it with `PUT /v1/company/logo` as PNG or JPEG. A later logo never changes an issued document. A document is never changed after it is issued. Each one carries a sha256 of its content, chained to the company's previous document, so a gap or an edit would show. Documents of one company are issued one after the other, so the chain never forks. ## Read them - `invoices.list {month}`: the documents of the company, newest first, with `kind`, `status`, `cancels_id` and `supplement_of`. - `invoices.get {id}`: one document as JSON, by id or number, with `prev_sha256`. - The PDF: `GET /v1/invoices/{id}/pdf` with the session token, in English, or German with `?lang=de`. Names in letters the PDF font lacks are written in Latin letters, the JSON keeps them as they are. - The archive: when a document is issued, its JSON and both PDFs go into an archive in the EU. The files are never overwritten. Every download is that archived file, and its sha256 comes in the `X-Archive-SHA256` header. - Everything at once: `GET /v1/company/export` returns a ZIP with every document, all receipts as `receipts.csv` and an index `documents.csv`. Your company keeps the duty to retain its records, and this file lets it do so on its own. ## Export for the books From Books on, every finished month comes for the books in two forms. Admins, owners, finance and the adviser call `GET /v1/invoices/export?month=2026-10` with `format=csv` or `format=datev`. A locked month is not exported. The ZIP of `GET /v1/company/export` holds both files for every month the plan covers, under `exports//`. **CSV:** one line per line of a document, with the number, kind, status, seller, level, description, calls, USDC and EUR, the rate in USD per EUR, the conversion method, the tax case and the sha256. A cancellation is one line with its amounts as a minus, so the month adds up. Overviews are listed, supplements name their first document in `supplement_of`. UTF-8, comma separated. **DATEV:** a Buchungsstapel in the DATEV format (EXTF, version 700, category 21, format version 13), Windows-1252, semicolon separated, for the import into DATEV Rechnungswesen. Two bookings per voucher, both on the last day of the month with the document number in Belegfeld 1: | Booking | Konto | Gegenkonto | BU-Schlüssel | |---|---|---|---| | Expense to the clearing account | SKR03 4900, SKR04 6300 | SKR03 1360, SKR04 1460 | 94 (§ 13b, 19 %), 95 for small businesses and exempt sales | | Clearing account to the USDC holding | SKR03 1360, SKR04 1460 | SKR03 1500, SKR04 1300 | none | A cancellation books its voucher back on the same accounts (Haben). Overviews are not booked. Buyers outside Germany get no tax key. Invoices and credit notes from sellers on level 2 and 3 take 9 (19 % input VAT, on the gross amount) for `domestic_19`, 506 for `eu_reverse_charge`, 511 for `third_country_reverse_charge` and none for `domestic_small_business`. The chart comes from `skr` in the company data. Bookings are not fixed (Festschreibung 0), so the adviser can still change them. **All accounts and tax keys are proposals until your tax adviser confirms them.** The adviser's own numbers go in the URL: `konto_aufwand`, `konto_verrechnung`, `konto_usdc`, plus `berater` and `mandant` (the numbers DATEV knows the firm and the company by, default 1001 and 1) and `wj_beginn` (start of the fiscal year, default 1 January). What each plan includes is on [Pricing](https://402lounge.com/pricing). # Paying 402lounge Source: https://402lounge.com/docs/billing > Three ways to pay for a plan, the archive, the sponsored place or the seller check. Polar with a card, your agent in USDC over x402, or your own transfer in USDC. What the invoice says. Books, Books for teams, the archive, the sponsored place and the seller check for level 2 can be paid three ways. All three give the same plan with the same limits. Prices are in EUR and include VAT, a year costs ten months. The sponsored place is one month, paid once. | What | Month | Year | |---|---|---| | Books | 29 € | 290 € | | Books for teams | 99 € | 990 € | | Archive, for companies without a plan | 5 € | 50 € | | Sponsored place | 49 € for one month, paid once | | | Seller check for level 2 | | 10 € per listing | The seller check is included in Books and Books for teams. Asking for it on a paid plan answers `check_included`. ## The archive Without a paid plan, the receipts and documents of a year are deleted on 31 January of the next year. The archive keeps them at 402lounge for a company that does not need Books: receipts, monthly documents and invoices stay as long as the archive runs, and 30 days after it ends. Nothing else changes, the company stays on Free with its limits and the monthly overview. Books and Books for teams keep the records anyway, so the archive is only for companies without a paid plan (`archive_with_plan`). - **Through Polar** it renews each month or year until you cancel. A company has one subscription at Polar: to move from the archive to Books, or back, switch it in the customer portal (`billing.portal`). Polar credits the rest of the period, and the new one starts at once. - **In USDC** it covers the period you pay. A period paid while the archive runs is added to its end. `GET /v1/billing` shows it in `archive`: whether it runs, until when, how it is paid and whether it renews. `company.get` says in `retention` what keeps the records (`by: "plan"` or `"archive"`) or when they go. A company that closes renews nothing any more, and a paid archive keeps its records until the first 31 January after the archive ends. ## Which way fits - **Polar.** Card, PayPal and more. Polar is the seller and issues the invoice. It renews a plan or the archive each period. The sponsored place and the seller check are paid once. `billing.checkout` gives a link for a person of your company. - **Your agent pays in USDC.** The agent asks for an offer and pays it over x402, from its own wallet. Nothing renews by itself. - **Your own transfer in USDC.** A person sends exactly the amount of the offer to our wallet on Base, from any wallet. Nothing renews by itself. `GET /v1/billing` lists the ways that are open right now in `pay_with`: `polar`, `usdc` or both. ## The offer `billing.quote` (or `POST /v1/billing/usdc/quote`) makes an offer for one item: ``` {"plan": "books", "period": "month"} {"archive": "year"} {"sponsor": ""} {"seller_check": ""} ``` Admins, owners and finance ask for offers. The company needs its name, address, country and confirmed email first, because the invoice names them. The answer has the price in EUR with the VAT for your company, the ECB rate of the day (USDC counts as USD, as on receipts) and `amount_usdc`. The digits after the cent are a marker: no other open offer has the same amount, so a plain transfer finds its offer. The offer is open for 30 minutes. Every company pays the price on the pricing page. What it holds follows where your company sits. - **Germany:** 19 % German VAT is in the price. - **Another EU country with a VAT ID confirmed by VIES:** the same price without VAT, reverse charge. Without a confirmed VAT ID the price holds 19 % German VAT, the offer says how to add one. - **Outside the EU:** the same price, not taxable in Germany, no VAT on the invoice. ## Your agent pays it The offer's `pay_url` is an x402 route. Without payment it answers 402 with the amount, our wallet and Base. Your x402 client pays it like any other paid call, and the answer says `paid` with the invoice. ``` npx awal x402 pay -X POST ``` Most x402 clients cap one payment at 1 USD by default. A plan costs more, so allow the amount of the offer for this one payment (for `@x402/core`: `client.setSpendControls({ maxAmountPerPayment: '$400' })`). The `pay_url` needs no sign-in: whoever pays it pays for your company. A paid offer is never charged twice. ## You send it yourself Send exactly `amount_usdc` in USDC on Base to `pay_to`, before `expires_at`. Any wallet works, it does not have to be in your company. We see the transfer within a minute or two of its block. `GET /v1/billing/usdc/quote/{id}` then says `paid`, with the invoice. A different amount, or a transfer after the offer ran out, unlocks nothing. We look at every such payment and write to you. Ask for a new offer instead of sending more. ## After the payment - The plan starts at once. Paying the same plan again adds its period to the end of the current one. - A different plan while one paid in USDC runs goes by hand: write to hello@402lounge.com and we credit the rest. - The archive runs from the payment, or from the end of the archive that runs. - The sponsored place runs for one month from the payment. A month paid while it runs is added to its end. - The seller check counts for a year from the payment, or from the end of the year already paid. The check of the listing then goes on by itself ([seller levels](https://402lounge.com/docs/sellers.md)). - Nothing renews by itself. We send a notice 7 days before the end. Without a new payment the plan falls back to Free at the change of month after it ends. ## The invoice Every payment in USDC gets an invoice from 402lounge (Florian Baraz, Cuxhaven), numbered like `R-2611-0017`: R, year and month, a running number per month. It names your company as on the offer, the item and its period, net, VAT or the note on reverse charge, the total in EUR, and the payment: the amount in USDC, the rate and the transaction on Base. `billing.invoices` (or `GET /v1/billing/invoices`) lists them, each with a PDF in English or German (`?lang=de`). We keep every invoice as issued. A mistake is corrected with an invoice correction, with its own number, and the original stays. These invoices are for payments in USDC. For what you bought through Polar, Polar issues the invoice. The one for the sponsored place or the seller check comes with Polar's confirmation email. For a plan or the archive you find it in Polar's customer portal (`billing.portal`). A payment of an offer has our invoice, so it does not show up again in your monthly documents. # For sellers Source: https://402lounge.com/docs/sellers > How an x402 service gets into the register, what we read from its 402 answer every night, and how it climbs the levels. When the register knows your wallet, the agents that pay you get receipts with your name on them, and their companies can book what they bought from you. Being listed and proving your wallet cost nothing. ## Get listed A listing names a service and the wallets it gets paid to. It belongs to a company, so the company's account comes first: your agent opens it with `lounge.signup`. 1. **Read one paid URL.** `directory.preview {url}` (or `POST /v1/listings/preview`) calls it once without paying and shows what the listing would say: name, description, price, logo and the wallet you get paid on, from your 402 answer. If the host or the wallet is in the directory already, the answer says so. Then claim that listing instead of listing it twice. 2. **Publish it.** An admin agent or the owner calls `directory.submit {url, contact_email}` (or `POST /v1/listings`). The listing goes live on level 0, under your company. The contact email is only for us. 3. **Prove the wallet,** below. The listing moves to level 1. Everything on a listing comes from your 402 answer, nothing is typed in by hand. To change the listing, change the answer. ## How the catalogue is filled Once a night we call the paid endpoint of every live listing without paying, to read what it sells and for how much: - With `GET`, then `POST` where the endpoint refuses `GET`, the user agent `402lounge-probe/1.0 (+https://402lounge.com)`, ten seconds to answer, no redirects followed. - A proper x402 server answers 402 with its payment requirements, in the `PAYMENT-REQUIRED` header or the body. - Every option in `accepts` is kept. The USDC option on Base gives the price and payTo for receipts, the other networks are shown on the listing. From `resource` we take the URL and the description. That fills the catalogue behind every receipt's "what was bought". If the payTo is not one of the listing's wallets, the check notes it, and the register shows the result as `last_check`. ## Prove your wallet Level 1 means the wallet itself proved it belongs to your listing. From then on your buyers' receipts carry your name, and `register.lookup` answers `verified`. `directory.claim {slug, address}` answers with a challenge for that wallet. Sign it with the wallet and call again with `wallet_proof {message, signature}`. The wallet signs one line: "Claim the 402lounge listing for company with this wallet." Over REST it is `POST /v1/listings/{slug}/claim`. Admin agents and owners claim. People of the company can do it from the app with a browser wallet. - **A listing nobody holds yet,** like the services we listed from their public 402 answers: a wallet the listing names claims it for your company. - **A listing your company holds:** another wallet proves itself the same way and is added on level 1. - **A listing another company holds** cannot be claimed. Write to hello@402lounge.com with the wallet. Proving a wallet by sending 0.01 USDC from it opens once 402lounge takes payments. ## Level 2, company checked Level 2 tells buyers and their tax advisers which company is behind a listing. The register and the listing then name your company and its country, and the receipts of your buyers name it too. A sole proprietor's name shows only if you allow it (`show_name`). It costs €10 a year per listing and is included in Books and Books for teams. `seller.get` (or `GET /v1/seller`) shows every listing with its level and what is missing. 1. **Company data.** The company is on level 2 as a buyer too: name, address, country and a confirmed email (`company.update`, `company.email`), and the VAT status (`company.update {vat_status}`). 2. **The person who acts for the company.** `seller.profile {representative_name}`, the role is optional. A commercial register entry (`register_court`, `register_number`) helps the approval but is not required, without one set `no_register: true`. A business that is one person sets `sole_proprietor: true`. 3. **Start the check.** `seller.check {action: "start", listing}` (or `POST /v1/seller/checks`). The listing needs a proved wallet (level 1). 4. **Confirm your domain.** `seller.check {action: "email", id, email}` sends a code to an address at the domain of the listing (the host or the domain above it, for example `billing@example.com` for `api.example.com`), `seller.check {action: "confirm_email", id, code}` confirms it. An agent without a mailbox adds the TXT record from the check instead: `_402lounge.` with the value `402lounge-verify=`, also on the domain above the host. A host on a hosting platform's domain (such as `vercel.app`) can only use the record. 5. **Run the steps.** `seller.check {action: "verify", id}` checks the company data, VIES for your VAT id (sellers in the EU, VIES does not cover others, a small business in Germany without a VAT id gives its tax number instead), the domain, the EU sanctions list and the payment. Each step says what is missing. 6. **Pay.** `seller.check {action: "checkout", id}` gives a Polar checkout for one year. Paying in USDC is the other way. With Books there is nothing to pay. 7. **Approval.** Once every step passed, a person at 402lounge looks at the company and approves the check, or tells you why not. You get a notice either way. The level runs one year. 30 days before the end you get a notice, the next check opens 60 days before. Without it the listing falls back to level 1. We screen sellers on level 2 against the EU sanctions list at the check and every night. A possible match waits for a person at 402lounge, nothing about it is decided automatically. ## Level 3, invoices in your name With the invoicing mandate, 402lounge issues invoices in your name and on your account to your buyers on 402lounge (§ 14 (2) UStG): one per buyer and month, numbered in your own range like `L-2610-10427-01`, with your seller number, each with its e-invoice. You remain the issuer. Read the mandate at [/mandate](https://402lounge.com/mandate) before you sign. - **Who gets one.** Buyers on level 3 (VAT ID confirmed by VIES) anywhere in the EU with Books or Books for teams, for what their agents paid your listings on level 2. Other buyers keep their own voucher, among them buyers outside the EU and, for now, buyers in your own state when that state is not Germany. - **What you need.** A listing on level 2, the VAT status of your company, and Books or Books for teams. - **Sign.** `seller.mandate {action: "sign"}` answers with a challenge. Sign it with your agent's wallet and call again with `agreement_proof {message, signature}`. An owner confirms it in the app. Version, time and signature are kept. - **Revoke.** `seller.mandate {action: "revoke"}` at any time. It ends at the end of the month, that month still gets its invoices. - **Your copies.** `seller.invoices` lists every invoice in your name, each with its PDF and its e-invoice (`GET /v1/seller/invoices/{id}/pdf` and `/xml`). Cancel one with `seller.invoices.cancel {id, reason}`. The VAT case follows your company and the buyer's: 19 % for a German seller and a German buyer, none with the note on § 19 UStG for a German small business, and across a border the reverse charge, the buyer owes the VAT in its own state (Art. 196 of the VAT Directive). The invoice follows the invoicing rules of your state if you are established in the EU and of the buyer's state if you are not (Art. 219a), and carries the mention "Reverse charge" with the term of that state. A seller outside the EU puts its tax id in the company data (`tax_number`). A seller and a buyer in the same state outside Germany still get the voucher, that case is not built yet. How the documents are built is in [Monthly documents](https://402lounge.com/docs/vouchers.md#invoices-and-credit-notes). ## Self-billing instead Without a mandate, a company on level 2 can agree that its buyers settle what they paid with a credit note (Gutschrift) instead of an invoice: `seller.self_billing {action: "sign"}`, on any plan. 402lounge prepares the credit note for the buyer, you get a copy in `seller.invoices`. A credit note follows the invoicing rules of the buyer's state and says "Self-billing" with the term of that state. Buyers in Italy, Hungary, Poland, Romania, Greece, Croatia and Portugal keep the voucher for now, their states run clearing or reporting systems that a credit note would have to pass. The other twenty states take credit notes. Object to a single credit note by cancelling it. Read the agreement at [/self-billing](https://402lounge.com/self-billing). ## What you see | Level | The listing and the register show | Your buyers get | |---|---|---| | 0 | The listing, marked listed | Receipts marked listed | | 1 | The wallet proved itself | Receipts with your listing | | 2 | Your company name and country | Receipts with your company, a voucher per month, or credit notes with self-billing | | 3 | Your company, invoicing | Invoices in your name, from Books on | Payments other companies make to your listings while the mandate runs count for the transaction limit of your plan, next to your own. ## The sponsored place A company whose listing is in the directory can book the one sponsored place: €49 for one month, paid once, through Polar or in USDC. `sponsor.checkout {listing}` (or `POST /v1/sponsor/checkout`) gives the checkout link, `sponsor.get` shows whether the place is free. Nothing renews by itself: while your place runs, the next month you book starts when it ends. The listing then stands first in the directory and in `directory.search`, marked Sponsored. It never changes the order or a level. [What the levels mean](https://402lounge.com/levels) and [pricing for sellers](https://402lounge.com/pricing?for=sellers) have the details. ## Make it easy for agents - Answer 402 to a request without payment, with a short description of the resource. That description ends up on receipts. - Pay out to the wallets on your listing and nowhere else, or the check says so. - Publish `/.well-known/x402` and `llms.txt`. The directory shows both on your card. # MCP tools Source: https://402lounge.com/docs/tools > Every tool of the MCP server with what it does, who may call it and its inputs, as tools/list returns them. The server at `https://mcp.402lounge.com/mcp` speaks Streamable HTTP and needs no key to connect. Calling a tool costs nothing. This page is written from what the server registers, so it names the same tools as `tools/list`. Tools that need an account also take `session_token`, `proof` and `client`, the sign-in fields from [Accounts and sign-in](https://402lounge.com/docs/accounts.md#ways-to-prove-who-you-are). A client that sends `Authorization: Bearer lg_...` needs none of them. The lists below leave these three fields out. A tool that fails returns `isError: true` with the error body of [Errors and limits](https://402lounge.com/docs/errors.md) in `structuredContent`. ## Account ### lounge.requirements **What you need to join.** Rules, prices, the current terms and the exact sentences you will sign. Free, no account. Who: No account. Inputs: none. ### lounge.terms **Current terms.** Versions, hashes and links of the terms and the privacy notice. With accept: true you confirm a new version: first call returns a challenge, second call with proof {message, signature} records it. Who: No account. Accepting a new version: the agent itself. Inputs: - `accept` (boolean, optional) ### lounge.signup **Create your account.** Free. Your account is a company from the first call, named after you until company.update adds the legal data. With invite_code you join an existing company instead. Proves your wallet with a signature: first call returns a challenge, second call with proof {message, signature} creates the account. Wallets that cannot sign pay 0.001 USDC over HTTP instead (pay_instead in the answer), once payments are open. Who: A wallet that signs, or pays 0.001 USDC. Inputs: - `name` (string, required): Your name as an agent, unique inside your company, e.g. "Research" - `invite_code` (string, optional): From company.invite, to join that company - `email` (email, optional): Optional: where documents and notices of your new company go. Ignored with invite_code. - `address` (string, optional): Your wallet address, so the challenge comes back as a finished message - `provider` (string, optional): awal, cdp, viem, other - `accept` (object {terms, privacy, business}, required) ### lounge.me **You and your company.** Who you are (agent and role), your company with its agents, people and level, its wallets, your apps, terms state and pending notices. Who: Anyone in the company. Inputs: none besides the sign-in fields. ### lounge.agent.update **Rename yourself.** Your name inside the company, 1 to 40 characters, unique in the company. Company data lives in company.update. Who: The agent itself. Inputs: - `name` (string, required) ### lounge.wallet.add **Add a wallet.** The new wallet proves itself: first call returns a challenge for it, second call with wallet_proof {message, signature} adds it. It belongs to your company and you operate it. How many follows the plan: Free 1, Books 5 per agent and 15 in all, Books for teams without limit. Who: Any agent. Inputs: - `address` (string, required) - `provider` (string, optional) - `wallet_proof` (object {message, signature}, optional) ### lounge.wallet.remove **Remove a wallet.** Your own wallets (admins: any wallet of the company). Not the one you sign in with, and never your last one. Sessions made with that wallet end. Its receipts stay. Who: Agents their own wallets. Admins and owners any. Inputs: - `address` (string, required) ### lounge.wallet.primary **Set your sign-in wallet.** The wallet you sign in with. It has to be assigned to you. Who: The agent itself. Inputs: - `address` (string, required) ### lounge.wallet.list **Wallets.** All wallets of your company, each with the agent that operates it. mine: true lists only yours. Who: Anyone in the company. Inputs: - `mine` (boolean, optional) ### lounge.session **Session tokens.** create: a new lg_ token (needs a signature or an existing token). list and revoke manage them. Who: The agent itself. Inputs: - `action` ("create", "list", "revoke", required) - `session_id` (id, optional) ### lounge.apps **Connected apps.** Which clients this agent has used. deactivate ends their sessions, activate turns them back on, disconnect forgets them. Who: The agent itself. Inputs: - `action` ("list", "deactivate", "activate", "disconnect", optional, default "list") - `app_client` (string, optional) ### lounge.notices **Notices.** Terms changes, moderation decisions, deletion and security notes, for you and for your company. ack marks one as read. Who: Anyone in the company. Inputs: - `action` ("list", "ack", optional, default "list") - `id` (integer, optional) - `all` (boolean, optional) ### lounge.dashboard.link **Dashboard link.** A one-time browser link (10 minutes) into your company's dashboard, signed in as you, for the human behind you. Who: The agent itself. Inputs: none besides the sign-in fields. ### lounge.account.export **Export your data.** Everything 402lounge keeps about you as an agent off chain, as JSON. The company's books come from receipts.list and invoices.list. Who: The agent itself. Inputs: none besides the sign-in fields. ### lounge.account.delete **Delete yourself.** Schedules your deletion as an agent in 7 days. cancel: true keeps you. Your wallets and receipts stay with the company. Needs a fresh signature with the delete statement (first call returns the challenge). Who: The agent itself, with a fresh signature. Inputs: - `confirm` (true, required) - `cancel` (boolean, optional) ## Receipts and register ### receipts.record **Report a payment you made.** Call this after every x402 payment: the transaction hash from the PAYMENT-RESPONSE header plus the URL you paid. 402lounge matches it with the transfer on Base and writes a receipt with the seller from the register, the catalogue description and a provisional EUR value. Free. Who: Any agent. Inputs: - `tx_hash` (string, required): The settlement transaction, 0x plus 64 hex characters - `resource_url` (URL, optional): The URL you paid for (the 402 resource) - `amount` (string, optional): What you paid, in USDC, e.g. "0.002" - `description` (string, optional): What you bought, in your words. The seller's catalogue wins when it knows the URL. - `pay_to` (string, optional): The payTo address from the payment requirements - `network` ("base", "base-sepolia", optional) - `payment_response` (string or object, optional): The raw PAYMENT-RESPONSE header, if you still have it ### receipts.list **Your company's receipts.** Receipts of your company for one month (default: the current month, Europe/Berlin), newest first, each with the agent that paid. Totals per seller and per agent, and the reports still waiting for the chain. mine: true, agent_id or wallet narrow it. Who: Anyone in the company. Inputs: - `month` (string, optional): Like 2026-10 - `status` ("verified", "listed", "unverified", optional): Only receipts with this seller status - `limit` (integer, optional) - `before` (integer, optional): Page: the smallest receipt id of the previous page - `mine` (boolean, optional): Only the receipts of wallets you operated - `agent_id` (id, optional): Only one agent of the company - `wallet` (string, optional): Only one paying wallet ### receipts.get **One receipt.** A single receipt of your company by id or transaction hash. Who: Anyone in the company. Inputs: - `id` (string, required): Receipt id or 0x transaction hash ### register.lookup **Who is behind this wallet?.** Wallet in, seller out: the listing that owns a payTo address, its verification level, its paid endpoints and the last health check. Free, no account. Call it before you pay someone new. Who: No account. Inputs: - `address` (string, required): A payTo address on Base ## Company ### company.get **Your company.** Legal data, VAT status, tier and level, what is missing for the next tier, its agents with this month's spending, its people and your role. Who: Anyone in the company. Inputs: none besides the sign-in fields. ### company.update **Fill in or change the company data.** Admins only. Your account starts as a company named after you. Add name, legal_form, address_line1, postal_code, city, country and email to make it a company that gets monthly vouchers, plus a VAT id (checked against VIES at once) for invoice_ready. Any subset works, and the answer lists what is still missing. Who: Admins and owners. Inputs: - `name` (string, optional): Legal name of the company, without the legal form - `legal_form` (string, optional): GmbH, UG, AG, e.K., Inc., ... - `address_line1` (string, optional) - `address_line2` (string, optional) - `postal_code` (string, optional) - `city` (string, optional) - `country` (string, optional): ISO 3166 two-letter code, e.g. DE - `vat_id` (string, optional): VAT id in the format of its country, like DE123456789 or ATU12345678 (GET /v1/countries). EU numbers are checked against VIES - `tax_number` (string, optional) - `vat_status` ("vat_id", "tax_number", "small_business", "exempt", "not_registered" or null, optional): How the company stands with VAT: vat_id, tax_number (registered, VAT id still to come), small_business (§ 19 UStG) exempt (only VAT-exempt sales) or not_registered (no VAT registration, the USA or another country without VAT). Decides the tax note on its documents - `skr` ("SKR03", "SKR04", "OWN", optional): Chart of accounts for exports. OWN takes own_accounts - `own_accounts` (object {expense, clearing, usdc} or null, optional): With skr OWN: the expense, clearing and USDC holding accounts of your chart, 4 to 8 digits - `currency` (string, optional): The currency amounts are shown in, next to USDC: EUR (default, the currency of the documents), USD, or any currency with an ECB reference rate - `fx_method` ("ecb_daily", optional): How USDC becomes EUR on documents. Today only ecb_daily (ECB reference rate of the payment day) - `email` (email, optional): Where documents and notices go. A code confirms it ### company.vat_check **Re-check the VAT id.** Asks VIES again and updates the tier. Admins, owners and finance. Who: Admins, owners and finance. Inputs: none besides the sign-in fields. ### company.email **The company email.** Where documents and notices go. start sets the address and mails a 6-digit code, confirm checks it, remove clears it (only while the account has no company data). Admins only. Who: Admins and owners. Inputs: - `action` ("start", "confirm", "remove", required) - `email` (email, optional) - `code` (string, optional) ### company.invite **Invite another agent.** Admins only. A code valid for seven days. A new agent signs up with lounge.signup {invite_code}, an agent with its own account calls company.join {code} and brings its wallets and receipts. Who: Admins and owners. Inputs: none besides the sign-in fields. ### company.join **Join a company.** With an invite code. Works while your own account has no company data, no vouchers and no other agents: your wallets, receipts and reports move into that company and your own account goes away. You join as an agent, and an admin there can make you admin. Who: An agent with an account of its own. Inputs: - `code` (string, required) ### company.agents **Agents of your company.** Every agent with its role, its wallets and what it paid this month (receipts, USDC, EUR). Who: Anyone in the company. Inputs: none besides the sign-in fields. ### company.agent.update **Rename an agent or change its role.** Admins change any agent, an agent may rename itself. role is admin or agent. The company always keeps an admin or an owner. Who: Admins and owners. An agent may rename itself. Inputs: - `agent_id` (id, required) - `name` (string, optional) - `role` ("admin", "agent", optional) ### company.agent.remove **Remove an agent.** Admins only. Schedules the agent's deletion in 7 days. Its wallets stay with the company, unassigned, and its receipts stay in the books. Who: Admins and owners. Inputs: - `agent_id` (id, required) ### company.wallet.assign **Move a wallet to another agent.** Admins only. agent_id null leaves the wallet unassigned. Receipts already written keep the agent that paid, new ones get the new agent. Sessions of the previous agent made with that wallet end. Who: Admins and owners. Inputs: - `address` (string, required) - `agent_id` (id or null, required) ### company.wallet.label **Name a wallet.** A name for the company's own lists, e.g. "Research budget". Agents may name their own wallets, admins any. label null clears it. Who: Agents their own wallets. Admins and owners any. Inputs: - `address` (string, required) - `label` (string or null, required) ### company.members **People in your company.** list shows them. invite adds a person by email with a role: owner (everything), finance (documents, VAT check, plan), adviser (reads and exports, changes nothing, for a tax adviser), viewer (reads). They sign in by email link. An address that is in another company already keeps its login and gets this company next to the others. role changes a role, remove takes someone out. Admins and owners only, except list. Who: Anyone in the company lists. Admins and owners change. Inputs: - `action` ("list", "invite", "role", "remove", optional, default "list") - `email` (email, optional) - `role` ("owner", "finance", "adviser", "viewer", optional) - `member_id` (id, optional) ### company.requests **The board: requests between people and agents.** Where the tax adviser or the team ask for things, like a receipt that is missing or a purchase nobody described. list shows open ones (status: done or all for more), show one with its answers (request_id), ask writes one (title, body, optional month like 2026-10 and receipt_id), answer replies (request_id, body) and opens it again, done and reopen change its status, delete takes it back. A new request mails the people who keep the books, an answer everybody in the thread. Whoever reads the receipts may use it. Who: Whoever reads the receipts. Who asked, owners and admins delete. Inputs: - `action` ("list", "show", "ask", "answer", "done", "reopen", "delete", optional, default "list") - `status` ("open", "done", "all", optional) - `request_id` (id, optional) - `title` (string, optional) - `body` (string, optional) - `month` (string, optional) - `receipt_id` (integer, optional) ### company.close **Close the company.** Admin agents and the owner. Closes the company in 30 days: name confirms it with the company name. Until then everything can be read and the export works (GET /v1/company/export), calls that write are refused with company_closing. Then agents, people, sign-ins, sessions and wallets are removed. Receipts and issued documents stay locked until their retention period ends. cancel: true keeps the company. now: true with export_kept: true closes at once and deletes the receipts and documents too, after you downloaded the export. Documents in a seller's name stay with the seller. Who: Admins and owners. Inputs: - `name` (string, optional): The company name, as confirmation - `cancel` (boolean, optional) - `now` (boolean, optional): Close at once and delete everything - `export_kept` (boolean, optional): With now: you downloaded the export and keep the records yourself ## Documents ### invoices.list **Your company's documents.** Monthly vouchers per seller (and later invoices), newest first. Optional month like 2026-10. Who: Anyone in the company. Inputs: - `month` (string, optional) - `limit` (integer, optional) ### invoices.get **One document.** The full document as JSON, by id or number, with where its archived files lie and their sha256. The PDF is at /v1/invoices/{id}/pdf with your session token. Who: Anyone in the company. Inputs: - `id` (string, required) ### invoices.issue **Issue the documents for a month.** Admins, owners and finance. Runs by itself every night for last month. Call it for an older finished month or after a cancellation. One document per seller: the monthly overview on Free, the voucher with the tax note on Books. Payments that arrive after a document get a supplement. Pairs with receipts that lack a EUR rate are skipped and listed. Needs the company data and a confirmed email (tier company). Who: Admins, owners and finance. Inputs: - `month` (string, optional): Finished month, default: last month ### invoices.draft **The month so far.** Drafts of the documents the month would get today, one per seller, with lines, totals and the tax case. Nothing is stored and there is no number. Default: the current month (Europe/Berlin). The PDF of a draft is at /v1/invoices/draft/pdf?month=&seller=. Who: Anyone in the company. Inputs: - `month` (string, optional) ### invoices.cancel **Cancel a document.** Admins, owners and finance. Issues a cancellation for a document, with your reason. The original keeps its number and turns to cancelled. Its payments are open again, so invoices.issue for that month (or the nightly run for last month) puts them in a new document. Who: Admins, owners and finance. Inputs: - `id` (string, required): Id or number of the document - `reason` (string, required) ## Directory ### directory.search **Find a seller in the directory.** Services that take x402 payments, with their level (0 listed, 1 wallet verified), what they offer (MCP, .well-known/x402, llms.txt) and a link. Search by name, description or host. filter: all, verified or mcp. sort: level, new or name. A booked sponsored place stands in sponsored, marked as such, and never changes the order or a level. Free, no account. Who: No account. Inputs: - `q` (string, optional): Words to look for, e.g. "on-chain data" - `filter` ("all", "verified", "mcp", optional) - `sort` ("level", "new", "name", optional) - `limit` (integer, optional) - `offset` (integer, optional) ### directory.get **One listing.** A listing with its wallets (network and level), what its calls cost, other networks it takes and its links. Company and location show from level 2 on. Free, no account. Who: No account. Inputs: - `slug` (string, required): The listing slug, e.g. glassnode ### directory.claim **Claim your listing.** Admin agents and owners. A wallet the listing names proves the service is your company's: first call returns a challenge for that wallet, second call with wallet_proof {message, signature} signed by it claims the listing. The wallet moves to level 1 and payments to it name the listing on receipts. A listing your company holds takes more wallets the same way. Who: Admins and owners, with a signature of the listing's wallet. Inputs: - `slug` (string, required): The listing slug, e.g. glassnode - `address` (string, required): A payTo wallet of the listing - `wallet_proof` (object {message, signature}, optional) ### directory.preview **Read a paid URL for a new listing.** We call one paid URL once without paying, read its 402 answer and show the listing it would make: name, description, price, logo and the wallet you get paid on. Says so when the host or the wallet is listed already, then claim that listing instead. Who: Anyone in a company. Inputs: - `url` (string, required): One https URL that answers 402 Payment Required ### directory.submit **List your service.** Admin agents and owners. Puts the service behind one paid URL into the directory on level 0, under your company: its payTo wallet on Base, the call and its price from the 402 answer. contact_email is only for us, never shown. Then prove the wallet with directory.claim for level 1. Who: Admins and owners. Inputs: - `url` (string, required) - `contact_email` (email, required) ## Plans and billing ### billing.get **Plan, limits and usage.** Your company's plan with its period and end, its limits (null means no limit), what it uses this month (transactions, agents, wallets), whether the one-time 20 % over the limit is used, whether the month is locked, the archive (keeps receipts and documents without a paid plan, archive) and what happens to them without either (retention). Who: Anyone in the company. Inputs: none besides the sign-in fields. ### billing.checkout **Choose a plan.** Admin agents, the owner and finance. A checkout link at Polar for Books or Books for teams (plan + period), monthly or yearly (a year costs ten months), or for the archive (archive: month or year, €5 a month or €50 a year), which keeps receipts and documents of a company without a paid plan. Polar is the seller: it charges, handles VAT, issues the invoice and renews until cancelled. The invoices are in Polar's customer portal (billing.portal). Hand the link to a person of your company. It starts once Polar confirms the payment. Who: Admins, owners and finance. Inputs: - `plan` ("books", "teams", optional) - `period` ("month", "year", optional) - `archive` ("month", "year", optional): The archive instead of a plan, monthly or yearly ### billing.portal **Billing portal.** Admin agents, the owner and finance. A link to Polar's customer portal: payment method, invoices, change or cancel the plan. Who: Admins, owners and finance. Inputs: none besides the sign-in fields. ### sponsor.get **The sponsored place.** Your company's sponsored places with status and dates, and whether the place is free. One sponsor at a time, first in the directory and in directory.search, marked Sponsored, never changing the order or a level. 49 € for one month, paid once. Who: Anyone in the company. Inputs: none besides the sign-in fields. ### sponsor.checkout **Book the sponsored place.** Admin agents and the owner of the company the listing belongs to. A checkout link at Polar for one month of the sponsored place, 49 €, paid once, nothing renews. The month starts once Polar confirms the payment. While your place runs, the next month you book starts when it ends. Who: Admins and owners of the company the listing belongs to. Inputs: - `listing` (string, required): Slug of your listing ### billing.quote **Pay 402lounge in USDC.** Admin agents, the owner and finance. An offer to pay in USDC on Base: a plan (plan + period), the archive for a company without a paid plan (archive: month or year), one month of the sponsored place (sponsor: your listing slug) or the seller check for level 2 (seller_check: your listing slug, one year). The price is net in EUR, with VAT for your company and the ECB rate of the day, and the amount in USDC is unique for 30 minutes. Pay it yourself with your x402 client on pay_url, or a person sends exactly amount_usdc to pay_to. 402lounge sends an invoice. Nothing renews by itself. With quote_id only: the status of that offer, with the invoice once paid. Who: Admins, owners and finance ask for an offer, anyone in the company reads one. Inputs: - `plan` ("books", "teams", optional) - `archive` ("month", "year", optional): The archive, monthly or yearly - `sponsor` (string, optional): Slug of your listing, for the sponsored place - `seller_check` (string, optional): Slug of your listing, for the seller check - `period` ("month", "year", optional) - `quote_id` (id, optional): Read an offer instead of asking for one ### billing.invoices **Invoices of 402lounge.** The invoices 402lounge issued to your company for payments in USDC, newest first, each with a PDF link (add ?lang=de for German). With id: one invoice with its full content. Plans bought through Polar get their invoice from Polar. Who: Anyone in the company. Inputs: - `id` (id, optional) ## Sellers ### seller.get **Your seller levels.** Your company as a seller: every listing with its level (0 listed, 1 wallet verified, 2 company verified, 3 invoicing), the company check and its steps, the seller profile (register entry, representative), the invoicing mandate and self-billing, and what is missing for the next level. Who: Anyone in the company. Inputs: none besides the sign-in fields. ### seller.profile **Representative and register entry.** Admin agents and owners. What level 2 needs on top of the company data: the name of the person who acts for the company (representative_name, the role is optional). The commercial register court and number help the check but are optional, no_register: true where there is none. sole_proprietor: true when the company is one person, then show_name says whether the register may show the name. Who: Admins and owners. Inputs: - `register_court` (string or null, optional): e.g. Amtsgericht Charlottenburg - `register_number` (string or null, optional): e.g. HRB 123456 - `no_register` (boolean, optional) - `representative_name` (string or null, optional) - `representative_role` (string or null, optional): e.g. Managing director - `sole_proprietor` (boolean, optional) - `show_name` (boolean, optional) ### seller.check **The company check of a listing (level 2).** Level 2 for a listing of your company on level 1: action start {listing} opens the check and returns its steps. The domain of the listing is proved by an email address at it: email {id, email} sends a code there, confirm_email {id, code} confirms it. Without a mailbox, add the DNS TXT record from the check instead (_402lounge., value 402lounge-verify=). verify {id} runs the steps again (company data with the name of the person who acts for the company, VIES, the domain, EU sanctions list, payment). Once all pass, 402lounge approves it, then the listing is on level 2 for a year. checkout {id} gives the Polar link for 10 € a year, included in Books. get {id}, withdraw {id}. Who: Admins and owners, checkout also finance, get anyone in the company. Inputs: - `action` ("start", "get", "verify", "email", "confirm_email", "checkout", "withdraw", required) - `listing` (string, optional): The listing slug, e.g. glassnode - `id` (id, optional) - `email` (string, optional): email: an address at the domain of the listing - `code` (string, optional): confirm_email: the six-digit code from the mail ### seller.mandate **Invoicing mandate (level 3).** Admin agents and owners. get shows the mandate text (link, version, sha256) and whether it is signed. sign: first call returns a challenge, sign it with your wallet and call again with agreement_proof {message, signature}. Then, with a listing on level 2 and Books, buyers on level 3 get monthly invoices in your name (§ 14 (2) UStG), issued by 402lounge. revoke ends it at the end of the month. Who: Admins and owners sign and revoke, an admin agent with a signature of its wallet, get anyone in the company. Inputs: - `action` ("get", "sign", "revoke", required) - `agreement_proof` (object {message, signature}, optional) - `confirm` (boolean, optional) ### seller.self_billing **Self-billing agreement.** Admin agents and owners. Without a mandate, a company on level 2 can agree that its buyers on level 3 issue credit notes (Gutschriften) for what they paid, on any plan. get, sign (challenge, then agreement_proof), revoke (at the end of the month). Who: Admins and owners sign and revoke, an admin agent with a signature of its wallet, get anyone in the company. Inputs: - `action` ("get", "sign", "revoke", required) - `agreement_proof` (object {message, signature}, optional) - `confirm` (boolean, optional) ### seller.invoices **Documents in your name.** Invoices 402lounge issued in your name (L-2610-10427-01), credit notes your buyers issued to you (G-...) and their cancellations, newest first, each with its e-invoice. With id the whole document. PDF and XML: GET /v1/seller/invoices/{id}/pdf and /xml. Who: Anyone in the company. Inputs: - `id` (string, optional) - `month` (string, optional) - `limit` (integer, optional) ### seller.invoices.cancel **Cancel a document in your name.** Admin agents, the owner and finance. Cancels an invoice in your name or a credit note you received, with a reason: a cancellation in your number range follows, the original stays. The payments are open again and the next monthly run issues them anew. Who: Admins, owners and finance. Inputs: - `id` (string, required) - `reason` (string, required) # REST API Source: https://402lounge.com/docs/api > The same functions as the MCP tools over plain HTTP, every route with the tool it matches. The base URL is `https://api.402lounge.com/v1`. Bodies are JSON objects, answers are JSON. Each route does what its tool does, with the same fields, so the [MCP tools](https://402lounge.com/docs/tools.md) describe the inputs. ## Proving who you are Send `Authorization: Bearer lg_...` with a session token, or the `SIGN-IN-WITH-X` header of an x402 client. A body may also carry `session_token` or `proof: {message, signature}`. Without any of them a route that needs an account answers `auth_required` with a challenge. [Accounts and sign-in](https://402lounge.com/docs/accounts.md) explains each way. `X-Client` names your client, like `claude-code 2.1`. It shows up in the agent's list of apps. `X-Company-Id` names the company a call of a person is for, when their login is in several companies. Without it the API takes the company used last. Agents never need it, see [one login, many companies](https://402lounge.com/docs/accounts.md#one-login-many-companies). Errors look the same as over MCP, with the HTTP status of [Errors and limits](https://402lounge.com/docs/errors.md). Browsers may only call the API from 402lounge.com and app.402lounge.com. ## Start and account | Route | Tool | What it does | |---|---|---| | `GET /v1/requirements` | `lounge.requirements` | Rules, prices, the current terms and the sentences you sign. No account | | `GET /v1/terms` | `lounge.terms` | The current terms and privacy notice. No account | | `POST /v1/signup` | `lounge.signup` | Create the account. Answers 402 with the challenge and, once open, a 0.001 USDC option | | `POST /v1/session` | `lounge.session` | A new session token, by signature or by 0.001 USDC | | `GET /v1/me` | `lounge.me` | You, your company and its wallets. For a person also `memberships` and `company_selected`. For a login of the app without a company, who you are and how to create one | | `PATCH /v1/me` | `lounge.agent.update` | Your name inside the company | | `GET /v1/apps` | `lounge.apps` | The clients you have used | | `POST /v1/apps/{client}/{action}` | `lounge.apps` | `deactivate`, `activate` or `disconnect` a client | | `GET /v1/notices` | `lounge.notices` | Your notices. `?all=1` includes the read ones | | `POST /v1/notices/{id}/ack` | `lounge.notices` | Mark a notice as read | | `POST /v1/dashboard-link` | `lounge.dashboard.link` | A one-time dashboard link for ten minutes | | `GET /v1/me/export` | `lounge.account.export` | Everything we keep about the agent, as a JSON file | | `POST /v1/me/delete` | `lounge.account.delete` | Schedule the deletion in 7 days, with a fresh signature | | `DELETE /v1/me/delete` | `lounge.account.delete` | Cancel the deletion | ## Wallets | Route | Tool | What it does | |---|---|---| | `GET /v1/wallets` | `lounge.wallet.list` | All wallets of the company. `?mine=1` for your own | | `POST /v1/wallets` | `lounge.wallet.add` | Add a wallet. It signs `wallet_proof` or pays 0.001 USDC. The owner adds one in the app by its signature, with `agent_id` or `null` for none | | `PATCH /v1/wallets/{address}` | `company.wallet.label` | Name a wallet, `label: null` clears it | | `DELETE /v1/wallets/{address}` | `lounge.wallet.remove` | Remove a wallet, its receipts stay | | `POST /v1/wallets/{address}/primary` | `lounge.wallet.primary` | The wallet you sign in with | | `POST /v1/wallets/{address}/assign` | `company.wallet.assign` | Move a wallet to another agent, `agent_id: null` unassigns it | ## Receipts and the register | Route | Tool | What it does | |---|---|---| | `POST /v1/receipts` | `receipts.record` | Report a payment you made | | `GET /v1/receipts` | `receipts.list` | One month of receipts. `?month=2026-10&status=&agent_id=&wallet=&mine=1&limit=&before=`, `recent=1` for the newest of any month | | `GET /v1/receipts/{id}` | `receipts.get` | One receipt by id or transaction hash | | `GET /v1/wallet-names` | | Your company's names for wallets outside the register | | `PUT /v1/wallet-names/{address}` | | Name a wallet you paid that no listing claims, `{name}`, 1 to 60 characters. Shows on your receipts as `seller.your_name` | | `DELETE /v1/wallet-names/{address}` | | Forget that name | | `GET /v1/register/{address}` | `register.lookup` | Who is behind a payTo wallet. No account | ## Directory and listings | Route | Tool | What it does | |---|---|---| | `GET /v1/listings` | `directory.search` | The directory. `?q=&filter=all|verified|mcp&sort=level|new|name&limit=&offset=`. A booked sponsored place comes in `sponsored`. No account, cached for a minute | | `GET /v1/listings/{slug}` | `directory.get` | One listing with its wallets, calls and prices, other networks and links. No account | | `POST /v1/listings/preview` | `directory.preview` | Read the 402 answer of one paid URL and show the listing it would make. Body `{url}` | | `POST /v1/listings` | `directory.submit` | List the service on level 0 under your company. Body `{url, contact_email}`. Admins and owners | | `POST /v1/listings/{slug}/claim` | `directory.claim` | A wallet of the listing signs, the listing belongs to your company on level 1. Body `{address, wallet_proof?}`. Admins and owners | ## Plans and billing | Route | Tool | What it does | |---|---|---| | `GET /v1/billing` | `billing.get` | Plan, period, end, status, limits, this month's usage, the one-time 20 %, `archive`, `retention` and `pay_with` | | `POST /v1/billing/checkout` | `billing.checkout` | A Polar checkout for `{plan: "books"|"teams", period: "month"|"year"}` or for the archive, `{archive: "month"|"year"}`. Admins, owners and finance | | `POST /v1/billing/portal` | `billing.portal` | Polar's customer portal: payment method, invoices, change or cancel. Admins, owners and finance | | `GET /v1/sponsor` | `sponsor.get` | Your sponsored places and whether the place is free | | `GET /v1/sponsor/ad` | | `?listing=`: the text of the listing's sponsored tile, or what it says without one, and the rules | | `PUT /v1/sponsor/ad` | | `{listing, title, body, url}`: the title keeps the listing's name, the text up to 140 characters, the link on the listing's domain or a subdomain. Changeable while the place runs | | `POST /v1/sponsor/checkout` | `sponsor.checkout` | A Polar checkout for one month of the sponsored place, `{listing}`, paid once. Admins and owners of the company the listing belongs to | | `POST /v1/billing/usdc/quote` | `billing.quote` | An offer to pay in USDC: `{plan, period}`, `{archive}`, `{sponsor}` or `{seller_check}`. Price in EUR with VAT, the amount in USDC, `pay_to` and `pay_url`, open for 30 minutes. Admins, owners and finance ([Paying 402lounge](https://402lounge.com/docs/billing.md)) | | `GET /v1/billing/usdc/quotes` | No tool | The company's last 50 offers with their status | | `GET /v1/billing/usdc/quote/{id}` | `billing.quote` | One offer: `open`, `paid` or `expired`, with the transaction and the invoice once paid | | `POST /v1/billing/usdc/pay/{id}` | No tool | The offer's x402 route. Without payment 402 with the amount, with `PAYMENT-SIGNATURE` paid, answers with the invoice. No account | | `GET /v1/billing/invoices` | `billing.invoices` | The invoices of 402lounge for payments in USDC, newest first | | `GET /v1/billing/invoices/{id}` | `billing.invoices` | One invoice with its full content | | `GET /v1/billing/invoices/{id}/pdf` | No tool | The invoice as PDF, `?lang=de` for German, from the archive | | `POST /v1/webhooks/polar` | No tool | Polar's events, signed after Standard Webhooks. Only for Polar | ## Company and people | Route | Tool | What it does | |---|---|---| | `GET /v1/company` | `company.get` | Data, level, what is missing, agents and people | | `PATCH /v1/company` | `company.update` | Fill in or change the company data, also `currency`, `skr` and `own_accounts` | | `GET /v1/countries` | | What a company states about its taxes, per country: name, format and example of the VAT number, the tax or register number, the small business scheme with its threshold, the statuses that fit. Every EU state and the USA, `general` for the rest. Public | | `GET /v1/currencies` | | The currencies a company can see its amounts in: EUR, USD and every currency with an ECB reference rate. Public | | `POST /v1/company/vat-check` | `company.vat_check` | Ask VIES again | | `POST /v1/company/email` | `company.email` | Set the email and mail a code | | `POST /v1/company/email/confirm` | `company.email` | Confirm the code | | `DELETE /v1/company/email` | `company.email` | Remove the email, only without company data | | `PUT /v1/company/logo` | | The logo as the request body: PNG, JPEG or WebP, up to 256 KB. PNG and JPEG also go onto the documents the company issues from then on. Owner or admin agent | | `DELETE /v1/company/logo` | | Remove the logo | | `GET /v1/logos/{company}/{file}` | | The logo file, public. `company.logo` in `GET /v1/company` is its path | | `GET /v1/company/agents` | `company.agents` | The agents with their wallets and this month's spending | | `PATCH /v1/company/agents/{id}` | `company.agent.update` | Rename an agent or change its role | | `DELETE /v1/company/agents/{id}` | `company.agent.remove` | Remove an agent in 7 days | | `GET /v1/company/sessions` | | The open session tokens of every agent: client, wallet, since, until | | `DELETE /v1/company/agents/{id}/sessions` | | End all session tokens of an agent. The agent itself, the owner or an admin agent | | `DELETE /v1/company/agents/{id}/sessions/{sid}` | | End one of them | | `POST /v1/company/invite` | `company.invite` | An invite code for seven days | | `POST /v1/company/join` | `company.join` | Join a company with a code | | `GET /v1/company/members` | `company.members` | The people in the company | | `POST /v1/company/members` | `company.members` | Invite a person with a role | | `PATCH /v1/company/members/{id}` | `company.members` | Change a person's role | | `DELETE /v1/company/members/{id}` | `company.members` | Take a person out | | `GET /v1/company/roles` | | The company's own roles, the fixed ones and the areas | | `POST /v1/company/roles` | | `{name, areas}`: a role with none, read or write per area (receipts also export). Owner or admin agent | | `PATCH /v1/company/roles/{id}` | | Rename it or change its areas | | `DELETE /v1/company/roles/{id}` | | Delete a role nobody has | | `GET /v1/company/export` | No tool | The company's books as one ZIP: every document as JSON and PDF, `receipts.csv`, `documents.csv`. Owner, admin, finance and adviser | | `POST /v1/company/close` | `company.close` | Close the company in 30 days. Body `{name}` with the company name. With `now: true, export_kept: true` it closes at once and deletes receipts and documents. Owner and admin | | `DELETE /v1/company/close` | `company.close` | Cancel the closing. Owner and admin | ## Board Requests between the people and agents of a company, for example the tax adviser asking for a missing receipt. Whoever reads the receipts reads and writes here. | Route | Tool | What it does | |---|---|---| | `GET /v1/requests` | `company.requests` | The requests, last active first. `?status=open` (default), `done` or `all`, plus `open`, the number still open | | `POST /v1/requests` | `company.requests` | `{title, body?, month?, receipt_id?}`: ask something. Mails the company email and everybody who exports or changes receipts | | `GET /v1/requests/{id}` | `company.requests` | One request with its answers | | `POST /v1/requests/{id}/replies` | `company.requests` | `{body}`: answer. Opens a done request again and mails everybody in the thread | | `PATCH /v1/requests/{id}` | `company.requests` | `{status: "done"}` or `"open"` | | `DELETE /v1/requests/{id}` | `company.requests` | Take it back. Who asked, the owner or an admin agent | ## Documents | Route | Tool | What it does | |---|---|---| | `GET /v1/invoices` | `invoices.list` | The documents, newest first. `?month=2026-10&limit=` | | `POST /v1/invoices/issue` | `invoices.issue` | Issue the documents for a finished month. Owner, admin and finance | | `GET /v1/invoices/draft` | `invoices.draft` | The month so far as drafts, one per seller. `?month=2026-11` | | `GET /v1/invoices/draft/pdf` | No tool | A draft as PDF. `?month=&seller=&lang=de` | | `POST /v1/invoices/{id}/cancel` | `invoices.cancel` | Cancel a document. Body `{reason}`. Owner, admin and finance | | `GET /v1/invoices/export` | No tool | A finished month for the books: `?month=2026-10&format=csv` (one line per document line) or `format=datev` (DATEV Buchungsstapel). From Books on. Owner, admin, finance and adviser. [Monthly documents](https://402lounge.com/docs/vouchers.md#export-for-the-books) | | `GET /v1/invoices/{id}` | `invoices.get` | One document as JSON | | `GET /v1/invoices/{id}/pdf` | No tool | The archived PDF, English or `?lang=de`, byte for byte as issued | | `GET /v1/invoices/{id}/xml` | No tool | The e-invoice of an invoice or credit note (EN 16931, UN/CEFACT CII), as archived. Vouchers have none | ## Sellers | Route | Tool | What it does | |---|---|---| | `GET /v1/seller` | `seller.get` | Your listings with their level, the company check, the seller profile, the mandate and self-billing | | `PATCH /v1/seller/profile` | `seller.profile` | The person who acts for the company (`representative_name`, required for level 2), register court and number (optional, or `no_register`), `sole_proprietor`, `show_name`. Admins and owners | | `POST /v1/seller/checks` | `seller.check` | Start the company check of a listing on level 1. Body `{listing}`. Admins and owners | | `GET /v1/seller/checks/{id}` | `seller.check` | The check with its steps, the domain email and the DNS record as the other way | | `POST /v1/seller/checks/{id}/email` | `seller.check` | Send a code to `{email}` at the domain of the listing. Admins and owners | | `POST /v1/seller/checks/{id}/email/confirm` | `seller.check` | Confirm it with `{code}`, then the steps run again. Admins and owners | | `POST /v1/seller/checks/{id}/verify` | `seller.check` | Run the steps again. Admins and owners | | `POST /v1/seller/checks/{id}/checkout` | `seller.check` | A Polar checkout for one year of the check (10 €). Admins, owners and finance | | `DELETE /v1/seller/checks/{id}` | `seller.check` | Withdraw a check that is open or in review | | `GET /v1/seller/mandate` | `seller.mandate` | The invoicing mandate: text, version, sha256, statement, whether it is signed | | `POST /v1/seller/mandate` | `seller.mandate` | Sign it. An admin agent: first the challenge, then `{agreement_proof}`. An owner in the app: `{confirm: true}` | | `DELETE /v1/seller/mandate` | `seller.mandate` | Revoke it, in force until the end of the month | | `GET /v1/seller/self-billing` | `seller.self_billing` | The self-billing agreement and whether it is signed | | `POST /v1/seller/self-billing` | `seller.self_billing` | Agree to it, as the mandate | | `DELETE /v1/seller/self-billing` | `seller.self_billing` | End it, in force until the end of the month | | `GET /v1/seller/invoices` | `seller.invoices` | Invoices in your name, credit notes you received and their cancellations. `?month=&limit=` | | `GET /v1/seller/invoices/{id}` | `seller.invoices` | One of them as JSON | | `GET /v1/seller/invoices/{id}/pdf` | No tool | Its PDF, English or `?lang=de` | | `GET /v1/seller/invoices/{id}/xml` | No tool | Its e-invoice | | `POST /v1/seller/invoices/{id}/cancel` | `seller.invoices.cancel` | Cancel it with `{reason}`. Admins, owners and finance | ## For agents that read first | Route | What it is | |---|---| | `GET /llms.txt` | Short instructions for agents on the API host | | `GET /skill.md` | Sign-up and the first receipt as a skill file | | `GET /.well-known/x402` | What is free and what costs 0.001 USDC, for x402 clients | | `GET /health` | Whether the API is up | ## Used by the website The website and the app call these. They are public, but not meant for agents. | Route | What it does | |---|---| | `POST /v1/auth/web3/challenge` | A sign-in challenge for the dashboard | | `POST /v1/auth/web3/verify` | Sign in to the dashboard with a wallet signature | | `POST /v1/auth/email/link` | An email link into the app. For an address without a company it starts the sign-up | | `POST /v1/companies` | A signed-in person creates a company and becomes its owner, also next to the companies they are in already. Body: the fields of `PATCH /v1/company`, `name` required, and `accept: {terms, privacy, business: true}` | | `POST /v1/help` | The Help button of the app: a signed-in person writes what went wrong, also before the company exists. Body: `message` (3 to 4000 characters), `page`, `context: {last_error, locale, screen}`. We answer by mail to the sign-in address. 20 a day per login | | `POST /v1/me/terms` | Accept the current terms in the app, `{accept: true}`, with `all: true` for every company of the person. For people, and for an agent signed in with its dashboard link | | `POST /v1/auth/sso` | Whether a work address `{email}` signs in with SSO. Answers `sso_not_available` (501) while SSO is off | | `POST /v1/reports` | Report a listing or an agent for illegal content or a breach of the terms | | `POST /v1/track` | Count a view or a click on a listing page, without cookies | | `GET /v1/stats` | Calls and lookups of the last days, as counts only | | `GET /v1/status` | Each part of the service (`indexer`, `fx`, `documents`, `api`) as `ok`, `degraded` or `down`, with the incidents of the last 30 days. A minute old at most | | `GET /v1/blog` | Published articles | | `GET /v1/blog/{slug}` | One article | | `GET /v1/changelog` | Published changelog entries | # Errors and limits Source: https://402lounge.com/docs/errors > One error shape for MCP and REST, every code the API answers with, and the limits on how often you may call. Every error has the same shape over MCP and REST. `error` is a stable code your agent can act on, `message` is a sentence for people, and some codes carry more fields. ``` { "error": "rate_limited", "message": "Too many requests. Try again in 41 seconds.", "retry_after": 41 } ``` Over REST the HTTP status matches the table below. Over MCP the tool result has `isError: true` and the same body in `structuredContent`. ## Proving who you are | Code | HTTP | Meaning and what to do | |---|---|---| | `auth_required` | 401 | No proof came with the call. The answer carries a fresh `challenge` and `how`. Sign it and call again | | `signature_invalid` | 401 | The signature or the message is not valid. Sign the message exactly as you got it | | `nonce_expired` | 401 | The challenge is older than five minutes. Ask for a new one | | `nonce_used` | 401 | The challenge or the signature was used before. Ask for a new one | | `statement_mismatch` | 401 | The message was made for another purpose. Use the challenge of this call | | `domain_mismatch` | 401 | The message was made for another site | | `wallet_mismatch` | 401 | A different wallet signed than the one the challenge is for | | `session_expired` | 401 | The token is unknown or older than 90 days. Make a new one with `lounge.session` | | `session_revoked` | 401 | The token was revoked | | `mfa_required` | 403 | This person turned on the two-step sign-in. The app asks for the code of the authenticator app, then the session counts | | `payment_invalid` | 402 | The x402 payment could not be settled | ## The state of your account | Code | HTTP | Meaning and what to do | |---|---|---| | `not_found` | 404 | No account has this wallet yet, or the thing you asked for does not exist. Sign up first with `lounge.signup` | | `wallet_unassigned` | 403 | The wallet belongs to a company, but no agent operates it. An admin assigns it with `company.wallet.assign` | | `agent_suspended` | 403 | The agent is suspended. Read the notice with `lounge.notices` and write to hello@402lounge.com to appeal | | `deletion_pending` | 409 | The agent's deletion is scheduled. Cancel it with `lounge.account.delete {cancel: true}` first | | `company_closing` | 409 | The company closes on the date in `closing.due_at`. Reading and the export still work. An admin or the owner cancels with `company.close {cancel: true}` | | `terms_outdated` | 409 | The terms changed. Accept the version in `current` with `lounge.terms {accept: true}`. People accept in the app (`POST /v1/me/terms`) | | `no_company` | 404 | A login of the app without a company. Create one with `POST /v1/companies`, or ask the owner of your company to add your email | | `not_a_member` | 403 | `X-Company-Id` names a company this login is not in. `GET /v1/me` lists yours under `memberships` | | `sso_not_available` | 501 | Sign-in with SSO is not switched on yet. Use the email link or Google | | `sso_not_found` | 404 | No company signs in with SSO at the domain of this address | | `domain_taken` | 409 | Another company signs in with SSO at this domain. One domain belongs to one company | | `email_unconfirmed` | 403 | Creating a company needs a login with a confirmed email address, by email link or Google | ## Rights in the company | Code | HTTP | Meaning and what to do | |---|---|---| | `agent_required` | 403 | Only an agent can do this. People read and manage, agents pay | | `not_allowed` | 403 | Your role may not do this. The answer names `your_role` | | `last_admin` | 409 | The company needs an admin agent or an owner. Make someone else admin or owner first | ## Input | Code | HTTP | Meaning and what to do | |---|---|---| | `validation_failed` | 400 | A field is missing or wrong. `issues` lists each one | | `address_invalid` | 400 | An address is 0x plus 40 hex characters | | `tx_hash_invalid` | 400 | A transaction hash is 0x plus 64 hex characters | | `name_invalid` | 400 | An agent name needs 1 to 40 characters | | `email_invalid` | 400 | The email address cannot be used. Use a real inbox | ## Wallets | Code | HTTP | Meaning and what to do | |---|---|---| | `wallet_taken` | 409 | The wallet already belongs to an account | | `last_wallet` | 409 | This is the agent's only wallet. Add another one first | | `wallet_is_primary` | 409 | The agent signs in with this wallet. Pick another one with `lounge.wallet.primary` first | | `wallet_not_assigned` | 409 | The wallet is not assigned to you. An admin can assign it | | `wallet_not_found` | 404 | The wallet does not belong to this company | | `wallet_proof_invalid` | 409 | The wallet has not proved itself yet | ## Plans and billing | Code | HTTP | Meaning and what to do | |---|---|---| | `plan_limit` | 409 | The plan covers no more agents or wallets. `what` says which (`agents`, `wallets`, `wallets_per_agent`), `limit` how many. A bigger plan covers more: `billing.checkout` | | `month_locked` | 409 | The company made more transactions in that month than its plan covers. Every receipt is there, the month's document and export wait for a plan that fits | | `plan_required` | 403 | The CSV and DATEV export come with Books. The ZIP of `GET /v1/company/export` stays open on every plan | | `already_subscribed` | 409 | The company has a plan or the archive running at Polar. Change or end it in the portal (`billing.portal`) | | `archive_subscribed` | 409 | The company pays the archive through Polar. Switch it to the plan in the portal (`billing.portal`), Polar credits the rest | | `archive_with_plan` | 409 | Books and Books for teams keep receipts and documents already. The archive is for companies without a paid plan | | `archive_running` | 409 | The archive paid in USDC or by agreement runs until `until`. Pay the next period in USDC, or book it through Polar once it ended | | `plan_by_agreement` | 409 | The company has a plan by agreement. Write to hello@402lounge.com to change it | | `no_customer` | 404 | The company has bought nothing at Polar yet, so there is no portal. Choose a plan first | | `billing_not_configured` | 503 | Buying is not open yet. Write to hello@402lounge.com | | `billing_unavailable` | 502 | Polar did not answer. Try again in a minute | | `sponsor_taken` | 409 | Another sponsor has the place right now. `sponsor.get` says when it is free | | `sponsor_busy` | 409 | The sponsored place changed this moment. Try again | | `listing_not_yours` | 403 | Only the company the listing belongs to can sponsor it. Claim the listing first | | `not_open` | 503 | Paying in USDC is not open yet, or not for this item. Pay through Polar instead (`billing.checkout`) | | `company_data_missing` | 409 | An invoice needs the company's name, address, country and confirmed email. `missing` lists what is not there. Add it with `company.update` | | `plan_running` | 409 | Another plan paid in USDC runs until `until`. Ask for the new plan from that day on, or write to hello@402lounge.com to switch now | | `fx_unavailable` | 503 | There is no current ECB rate to price the offer. Try again in an hour | | `quote_expired` | 410 | The offer ran out after 30 minutes. Ask for a new one, do not send money for the old one | | `facilitator_unavailable` | 503 | The x402 facilitator does not answer right now. Send the amount yourself, or try again in a minute | | `payment_used` | 409 | That transaction already paid another offer | ## Directory and listings | Code | HTTP | Meaning and what to do | |---|---|---| | `listing_not_found` | 404 | No listing with that slug in the directory | | `listing_claimed` | 409 | Another company holds the listing. If the service is yours, write to hello@402lounge.com | | `wallet_not_listed` | 409 | The wallet is not one of the listing's wallets. Claim with one it names | | `already_listed` | 409 | The host or the payTo wallet is in the directory already. `listing` names it, claim it instead | | `slug_taken` | 409 | A listing with that name was added a moment ago. Try again | | `url_invalid` | 400 | Use the full public https address of one paid call | | `url_unreachable` | 422 | We could not reach the URL in ten seconds. Check that it is public | | `not_402` | 422 | The URL answered something else than 402. `status` says what. Use the URL of a call that costs money | | `payment_unreadable` | 422 | A 402 came back without payment details we can read | | `no_base_offer` | 422 | The 402 answer offers no payment on Base. Receipts cover Base, so the directory lists services that take USDC there | ## Seller levels | Code | HTTP | Meaning and what to do | |---|---|---| | `level_1_required` | 409 | The company check builds on level 1. Prove a wallet of the listing first with `directory.claim` | | `listing_without_domain` | 409 | The listing has no https address whose domain could be confirmed. Write to hello@402lounge.com | | `email_domain_mismatch` | 400 | The address for the domain check is not at the domain of the listing. `domains` lists where it may be, empty for a host on a hosting platform, which uses the DNS record | | `check_running` | 409 | A check of this listing was started a moment ago. `seller.get` shows it | | `check_valid` | 409 | The listing is on level 2 already. `valid_until` says until when, the yearly check opens 60 days before | | `check_closed` | 409 | The check is approved, rejected, expired or withdrawn. Start a new one with `seller.check {action: "start"}` | | `check_incomplete` | 409 | Not every step of the check passed. `failed` names them | | `check_included` | 409 | The plan includes the check, there is nothing to pay | | `check_paid` | 409 | The check is paid already | | `buyer_records_gone` | 409 | The buyer no longer keeps its records of the document at 402lounge, so a cancellation would not reach it. Write to hello@402lounge.com | | `level_2_required` | 409 | The invoicing mandate and self-billing need a listing on level 2 first | | `vat_status_required` | 409 | State the VAT status of the company first with `company.update {vat_status}`. Invoices in your name need it | | `agent_must_sign` | 400 | An agent signs the statement with its wallet: call again with `agreement_proof {message, signature}` | | `no_einvoice` | 404 | The document has no e-invoice. Invoices and credit notes have one, vouchers and overviews do not | | `einvoice_invalid` | 500 | The e-invoice of a document did not pass our check, so the document was not issued. We look into it, the next run issues it | | `sanctions_unavailable` | 502 | The EU sanctions list could not be loaded. Our side, the next run tries again | | `sanctions_unreadable` | 502 | The EU sanctions list came in a form we cannot read. Our side | ## Company, agents and people | Code | HTTP | Meaning and what to do | |---|---|---| | `name_taken` | 409 | An agent with that name already works for this company. Pick another name | | `invite_invalid` | 404 | The invite code is unknown, used or expired | | `company_exists` | 409 | The agent belongs to a company with its own data and cannot join another one. An agent's dashboard login cannot create a company | | `shell_has_documents` | 409 | The account has vouchers already and cannot fold into another company | | `shell_has_agents` | 409 | Other agents work for the account, so it cannot fold into another company | | `shell_has_members` | 409 | People are members of the account, so it cannot fold into another company | | `email_required` | 409 | A company with its data needs an email. Change it instead of removing it | | `code_invalid` | 400 | The email code (company email or domain check) is not right. The answer says how many tries are left | | `code_expired` | 400 | The email code is older than 15 minutes. Start again | | `too_many_attempts` | 429 | Five wrong codes. Start again for a new one | | `member_exists` | 409 | That address is a member already | | `member_not_found` | 404 | No member with that id in this company | | `agent_not_found` | 404 | No agent with that id works for this company | | `role_not_found` | 404 | No role with that id in this company | | `role_name` | 400 | A role name has 2 to 40 characters and is not the name of a fixed role | | `role_areas` | 400 | Every area needs a level, and the role reads at least one | | `role_exists` | 409 | The company has a role with that name already | | `role_in_use` | 409 | People have this role. Give them another one first | | `request_not_found` | 404 | No request with that id on the board of this company | | `ad_title` | 400 | The title of the sponsored tile needs 3 to 60 characters | | `ad_title_name` | 400 | The title keeps the listing's name. The answer names it | | `ad_body` | 400 | The text of the tile has at most 140 characters | | `ad_url` | 400 | The link of the tile starts with https:// | | `ad_url_domain` | 400 | The link goes to the listing's domain or a subdomain of it. `allowed` lists them | | `logo_too_large` | 413 | The logo has more than 256 KB. Save it smaller | | `logo_type` | 415 | A logo is a PNG, JPEG or WebP image | | `storage_unavailable` | 503 | The file store does not answer. Try again later | | `app_not_found` | 404 | No app with that client name is connected | | `confirmation_mismatch` | 400 | To close the company, send its name exactly as `company.get` shows it | | `vat_id_format` | 400 | The VAT number does not have the format of its country. The answer has `format` and `example` | | `vat_check_unavailable` | 400 | VIES checks VAT numbers of EU states only | | `currency_unknown` | 400 | The ECB publishes no reference rate for that currency. `GET /v1/currencies` lists the ones that work | | `export_not_confirmed` | 400 | Closing at once deletes the records. Download the export and send `export_kept: true` | | `close_not_scheduled` | 409 | The company is not closing, so there is nothing to cancel | ## Receipts and documents | Code | HTTP | Meaning and what to do | |---|---|---| | `report_duplicate` | 409 | Your company reported this transaction already. `receipts.list` shows its state | | `receipt_not_found` | 404 | No receipt with that id or hash in this company | | `month_open` | 400 | The month is not over yet in Europe/Berlin. Documents are issued for finished months, `invoices.draft` shows the month so far | | `document_not_cancellable` | 409 | The document is already cancelled, or it is a cancellation itself. To correct a month, issue it again | ## Our side | Code | HTTP | Meaning and what to do | |---|---|---| | `rate_limited` | 429 | Too many calls. Wait `retry_after` seconds | | `internal` | 500 | Something broke on our side. Try again later, and write to us if it stays | ## Rate limits Limits stop runaway scripts, they are not a quota for normal use. A call over the limit answers `rate_limited` with `retry_after`. | What | Limit | Counted per | |---|---|---| | `register.lookup`, `GET /v1/register/{address}` | 120 a minute | IP address | | `receipts.record`, `POST /v1/receipts` | 600 an hour | Agent | | `POST /v1/signup` | 5 an hour and 20 a day | IP address | | `POST /v1/session` | 20 an hour | IP address | | `POST /v1/wallets` | 10 a day | Agent | | `POST /v1/dashboard-link` | 10 an hour | Agent | | `company.update` | 30 an hour | Caller | | `company.vat_check` | 10 an hour | Caller | | `company.email` with `start` | 5 an hour | Caller | | `company.invite` | 20 a day | Caller | | `company.join` | 10 an hour | Agent | | `company.members` with `invite` | 20 a day | Caller | | `company.requests` with `ask`, `POST /v1/requests` | 30 an hour | Caller | | `company.requests` with `answer`, `POST /v1/requests/{id}/replies` | 120 an hour | Caller | | `invoices.issue` | 10 an hour | Caller | | `invoices.cancel` | 20 an hour | Caller | | `seller.check` | 20 an hour | Caller | | `seller.profile` | 30 an hour | Caller | | `seller.mandate`, `seller.self_billing` with `sign` or `revoke` | 20 an hour | Caller | | Dashboard sign-in, challenge and verify | 30 a minute each | IP address | | Email sign-in link | 5 an hour | IP address | | `POST /v1/reports` | 5 an hour | IP address | ## Other limits | What | Limit | |---|---| | Agents and wallets | By plan, see below | | Session tokens | 10 per agent, 90 days each | | Challenges | Five minutes, once | | Invite codes | Seven days | | Email codes | 15 minutes, five tries | | Dashboard links | Ten minutes, once | | Agent names | 1 to 40 characters, unique in the company, case ignored | | Pages | `limit` up to 200 for `receipts.list` and `invoices.list` | | Deletion | Takes effect after 7 days, until then it can be cancelled | ## Plans and their limits | Plan | Agents | Wallets | Transactions a month | |---|---|---|---| | Free | 1 | 1 | 500 | | Books | 3 | 5 per agent, 15 in all | 30,000 | | Books for teams | No limit | No limit | 500,000 | | Enterprise | By agreement | By agreement | By agreement | Transactions are the company's receipts in a calendar month, Europe/Berlin. A new agent (`company.invite`, a sign-up with `invite_code`, `company.join`) and a new wallet (`lounge.wallet.add`, `company.wallet.assign`) past the plan answer `plan_limit`. Over the transaction limit nothing is lost: every receipt is written. The first time a company goes over, 20 % more are covered until the end of that month, once. Past that, the month's document and its export wait until the plan fits, then they open (`month_locked` until then). A notice goes to the company and its agents at 80 % and at 100 % of the limit, and when a month locks. A month keeps the limits of the highest plan it ran under, so a downgrade later does not lock a month that was paid for. `billing.get` shows the usage, the allowance and whether the one-time 20 % is used. A paid plan that ends falls back to Free at the next month change, so the month it ran into still gets its voucher.