# Errors and limits > 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.