# Approve a command-line sign-in (https://docs.layerbeat.com/api/account/authorizeCliLogin) ## POST /v1/auth/cli/authorize Approves `layerbeat login` from the console and returns a single-use code for the command-line tool. **Access:** Signed-in browser session only. Bearer sessions and API keys can't approve. ### Details - The command-line tool sends the SHA-256 challenge of a secret it keeps (PKCE, method `S256`). The code is useless without that secret. - With `redirect_uri`, the console sends the code to the tool on this computer (`http://127.0.0.1:/callback` or `http://localhost:/callback` only). Without it, the console shows the code to paste into the terminal. - The code works once and expires after 5 minutes. Request and response schemas: https://layerbeat.com/openapi.yaml # Sign in (browser session) (https://docs.layerbeat.com/api/account/browserLogin) ## POST /v1/auth/browser/login Signs the browser in with an email and password using secure session cookies. **Access:** Layerbeat browser origin. ### Details - When Turnstile is enabled, each login attempt needs a fresh proof with action `login`. - Cookie-authenticated writes require `X-CSRF-Token`. See the [authentication guide](https://docs.layerbeat.com/guides/authentication/). Request and response schemas: https://layerbeat.com/openapi.yaml # Create an account (browser session) (https://docs.layerbeat.com/api/account/browserSignup) ## POST /v1/auth/browser/signup Registers an account and signs the browser in using secure session cookies. **Access:** Layerbeat browser origin. ### Details - Set `billing_currency` to save USD or IDR as the default. Registration does not add credit. - When Turnstile is enabled, include a fresh proof with action `signup`. - Cookie-authenticated writes require `X-CSRF-Token`. See the [authentication guide](https://docs.layerbeat.com/guides/authentication/). Request and response schemas: https://layerbeat.com/openapi.yaml # Finish account setup (https://docs.layerbeat.com/api/account/completeAccountOnboarding) ## POST /v1/me/onboarding Finishes account setup with your workspace name, billing currency and optional referral code. **Access:** User session: owner of the signup workspace. API keys aren't supported. ### Details - A referral captured during signup is kept. Add a manual code before your first purchase. - Repeated requests return the saved setup result. They do not rename the workspace or change preferences. - If this account does not need onboarding, use workspace and account settings instead (`409`). - IDR must be enabled. Setup does not add credit or create a VPS. - Browser requests need the Layerbeat origin and `X-CSRF-Token`. Request and response schemas: https://layerbeat.com/openapi.yaml # Confirm email ownership (https://docs.layerbeat.com/api/account/confirmEmailVerification) ## POST /v1/auth/email/confirm Verifies your email using a valid, unused verification token. **Access:** Verification token. No session required. ### Details - First verification signs out other sessions and removes previously created API keys and linked sign-ins. Your current session can be retained if included in the request. - This does not create a new session. Invalid, expired and used tokens return the same error. Request and response schemas: https://layerbeat.com/openapi.yaml # Recover account password (https://docs.layerbeat.com/api/account/confirmPasswordRecovery) ## POST /v1/auth/recovery/confirm Resets your password and revokes existing sessions, API keys and linked sign-ins. **Access:** Password recovery token. No session required. ### Details - The token can be used once and also verifies email ownership. Sign in with the new password afterward. - Keys are revoked across all workspaces. A security email and audit events record the reset. Request and response schemas: https://layerbeat.com/openapi.yaml # Create an API key (https://docs.layerbeat.com/api/account/createApiKey) ## POST /v1/api-keys Creates an API key with the scopes you choose. Save the secret; it is shown only once. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - A workspace can have at most 20 active keys. - A key cannot exceed its creator's current role. Removing the member, password recovery or first email verification revokes their keys. Request and response schemas: https://layerbeat.com/openapi.yaml # Disconnect a sign-in provider (https://docs.layerbeat.com/api/account/disconnectSocialAccount) ## DELETE /v1/auth/social/{provider}/connection Disconnects Google or GitHub from your account. **Access:** User session and a sign-in within the last 15 minutes. API keys are not supported. ### Details - Keep a password or another enabled sign-in provider. You cannot remove the last usable login method. - Browser requests need the Layerbeat origin and `X-CSRF-Token`. Request and response schemas: https://layerbeat.com/openapi.yaml # Exchange a legacy browser session (https://docs.layerbeat.com/api/account/exchangeBrowserSession) ## POST /v1/auth/browser/exchange Replaces a bearer session token with a secure browser cookie session. **Access:** Bearer user session and Layerbeat browser origin. API keys are not supported. ### Details - The original token is revoked. Cookie-only requests cannot use this exchange. Request and response schemas: https://layerbeat.com/openapi.yaml # Finish a command-line sign-in (https://docs.layerbeat.com/api/account/exchangeCliLogin) ## POST /v1/auth/cli/token Exchanges an approval code and its PKCE verifier for a command-line session. **Access:** Public. No authentication required. ### Details - The session acts as you, is named after the device (for example `layerbeat on riz-mbp`) and lasts 30 days from its last use, at most one year. - A wrong, used or expired code returns `400 invalid_grant` without saying which. - See active sessions with `GET /v1/auth/sessions` and sign one out with `DELETE /v1/auth/sessions/{id}`. Request and response schemas: https://layerbeat.com/openapi.yaml # Finish provider authorization (https://docs.layerbeat.com/api/account/finishSocialSignIn) ## GET /v1/auth/social/{provider}/callback Completes Google or GitHub sign-in and redirects to the Layerbeat console. **Access:** Provider redirect with the original browser cookies and valid state. ### Details - The provider calls this URL after authorization. It cannot be used as an API-key login. - Failed or expired flows redirect with a public error code. Return destinations are fixed by Layerbeat. Request and response schemas: https://layerbeat.com/openapi.yaml # Get account setup status (https://docs.layerbeat.com/api/account/getAccountOnboarding) ## GET /v1/me/onboarding Returns your account setup status and any saved referral code. **Access:** User session. API keys aren't supported. ### Details - Setup stays attached to the workspace created at signup, even if you switch workspaces. - Accounts that do not need onboarding return `required: false`. Request and response schemas: https://layerbeat.com/openapi.yaml # Read your workspace email preferences (https://docs.layerbeat.com/api/account/getEmailPreferences) ## GET /v1/notifications/preferences Returns your email preferences for the current workspace. **Access:** User session. API keys aren't supported. ### Details - Account security emails stay enabled. Product announcements are opt-in. Request and response schemas: https://layerbeat.com/openapi.yaml # Who am I (https://docs.layerbeat.com/api/account/getMe) ## GET /v1/me Returns your account, workspace and effective permissions. Use it to check a new API key. **Access:** User session or API key. Request and response schemas: https://layerbeat.com/openapi.yaml # Get personal billing currency (https://docs.layerbeat.com/api/account/getPersonalPreferences) ## GET /v1/me/preferences Returns your saved billing currency. **Access:** User session. API keys aren't supported. ### Details - An Indonesia location hint can suggest IDR before you choose a preference. It does not restrict your choice. - VPS prices come from the catalog. The returned accounting reference does not convert your balances or set retail prices. Request and response schemas: https://layerbeat.com/openapi.yaml # Get browser security-check configuration (https://docs.layerbeat.com/api/account/getTurnstileConfiguration) ## GET /v1/auth/turnstile Returns the public settings for account verification widgets. **Access:** Public. No authentication required. ### Details - When enabled, signup, login and recovery require a fresh `cf-turnstile-response` for the matching action. - The response contains the enabled flag and site key. It is not cached. Request and response schemas: https://layerbeat.com/openapi.yaml # List API keys (https://docs.layerbeat.com/api/account/listApiKeys) ## GET /v1/api-keys Lists your workspace's API keys without exposing their secrets. **Access:** User session: workspace admin or owner. API keys aren't supported. Request and response schemas: https://layerbeat.com/openapi.yaml # List your recent email delivery status (https://docs.layerbeat.com/api/account/listEmailHistory) ## GET /v1/notifications/email-history Lists recent email delivery status for your account and current workspace. **Access:** User session. API keys aren't supported. ### Details - Returns up to 50 entries from the last 30 days, including account security emails. - `sent` means the email provider accepted it. `delivered` requires a provider delivery event. Message bodies and private links are not included. Request and response schemas: https://layerbeat.com/openapi.yaml # List your sessions (https://docs.layerbeat.com/api/account/listSessions) ## GET /v1/auth/sessions Lists your signed-in sessions: the console and the command-line tool. Secrets are never returned. **Access:** User session. API keys aren't supported. Request and response schemas: https://layerbeat.com/openapi.yaml # List your connected sign-in accounts (https://docs.layerbeat.com/api/account/listSocialConnections) ## GET /v1/auth/social/connections Lists your connected sign-in providers and whether your account has a password. **Access:** User session. API keys aren't supported. ### Details - Connections belong to your account and follow you across workspaces. Request and response schemas: https://layerbeat.com/openapi.yaml # List social sign-in availability (https://docs.layerbeat.com/api/account/listSocialProviders) ## GET /v1/auth/social/providers Lists available Google and GitHub sign-in options and registration billing currencies. **Access:** Public. No authentication required. ### Details - Unavailable providers cannot start sign-in. An IDR suggestion does not restrict your currency choice. Request and response schemas: https://layerbeat.com/openapi.yaml # Sign in (https://docs.layerbeat.com/api/account/login) ## POST /v1/auth/login Signs in with an email and password and returns a session token. **Access:** Public. No authentication required. ### Details - An unknown email and a wrong password both return `401 invalid_credentials`. Repeated failures are throttled. - When Turnstile is enabled, each attempt needs a fresh proof with action `login`. Request and response schemas: https://layerbeat.com/openapi.yaml # Sign out (https://docs.layerbeat.com/api/account/logout) ## POST /v1/auth/logout Signs out the current session immediately. **Access:** User session. API keys aren't supported. Request and response schemas: https://layerbeat.com/openapi.yaml # Request email verification (https://docs.layerbeat.com/api/account/requestEmailVerification) ## POST /v1/auth/email/request Sends a single-use email verification link to your account. **Access:** User session. API keys aren't supported. ### Details - Requests are throttled. Repeated or unnecessary requests return the same accepted response. Request and response schemas: https://layerbeat.com/openapi.yaml # Request password recovery (https://docs.layerbeat.com/api/account/requestPasswordRecovery) ## POST /v1/auth/recovery/request Sends a password reset link if the email belongs to an account. **Access:** Public. No authentication required. ### Details - The link expires after 30 minutes. All addresses receive the same accepted response; requests are rate limited. - When Turnstile is enabled, include a fresh proof with action `recovery`. Request and response schemas: https://layerbeat.com/openapi.yaml # Revoke an API key (https://docs.layerbeat.com/api/account/revokeApiKey) ## DELETE /v1/api-keys/{id} Revokes an API key immediately. **Access:** User session: workspace admin or owner. API keys aren't supported. Request and response schemas: https://layerbeat.com/openapi.yaml # Sign out a session (https://docs.layerbeat.com/api/account/revokeSession) ## DELETE /v1/auth/sessions/{id} Signs out one of your sessions, for example a command-line tool on a computer you no longer use. Signing out the current session signs you out. **Access:** User session. API keys aren't supported. Request and response schemas: https://layerbeat.com/openapi.yaml # Save your workspace email preferences (https://docs.layerbeat.com/api/account/saveEmailPreferences) ## PUT /v1/notifications/preferences Updates your email preferences for the current workspace. **Access:** User session. API keys aren't supported. ### Details - Supply all four preference flags. Account security emails cannot be disabled. - Changes apply to future messages and queued messages that have not been sent. Browser writes need `X-CSRF-Token`. Request and response schemas: https://layerbeat.com/openapi.yaml # Create an account (https://docs.layerbeat.com/api/account/signup) ## POST /v1/auth/signup Registers an account and returns a session token for API access. **Access:** Public. No authentication required. ### Details - Creates an initial workspace and an empty personal wallet. Set `billing_currency` to save the account's USD or IDR preference. - Passwords must be 10–72 bytes. Signup is limited to 10 requests per minute per IP. - When Turnstile is enabled, include a fresh proof with action `signup`. Request and response schemas: https://layerbeat.com/openapi.yaml # Start social sign-in or connect a provider (https://docs.layerbeat.com/api/account/startSocialSignIn) ## POST /v1/auth/social/{provider}/start Starts Google or GitHub sign-in, or connects a provider to your existing account. **Access:** Layerbeat browser. Linking requires a user session and a sign-in within the last 15 minutes. ### Details - Open the returned `authorization_url` in the same browser. - Use `action: signin` to sign in or register, and `action: link` to connect an existing account. Linking needs `X-CSRF-Token`. - An email that already belongs to an account requires that account's login and explicit linking. - Workspace, referral and currency choices apply only to new registrations. Request and response schemas: https://layerbeat.com/openapi.yaml # Save personal billing currency (https://docs.layerbeat.com/api/account/updatePersonalPreferences) ## PATCH /v1/me/preferences Saves USD or IDR as your default billing currency across devices and workspaces. **Access:** User session. API keys aren't supported. ### Details - IDR must be enabled. Changing the default does not exchange credit or alter existing purchases and payments. - Browser requests need the Layerbeat origin and `X-CSRF-Token`. Request and response schemas: https://layerbeat.com/openapi.yaml # Activate customer referrals (https://docs.layerbeat.com/api/affiliates/activateAffiliate) ## POST /v1/affiliates Activates Refer & Earn and returns your workspace's eight-character referral code. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Returns `503 referrals_paused` while Refer & Earn is coming soon. - Repeated activation returns the same code. Activation alone does not award credit or earnings. Request and response schemas: https://layerbeat.com/openapi.yaml # Apply to become an affiliate partner (https://docs.layerbeat.com/api/affiliates/applyAffiliatePartner) ## POST /v1/affiliates/application Submits your website or community and promotion plan for affiliate partner review. **Access:** Verified user session: workspace admin or owner. ### Details - Returns `503 referrals_paused` while Refer & Earn is coming soon. - Activate the referral account first and supply an HTTPS URL. Earlier credit rewards remain nonwithdrawable. Request and response schemas: https://layerbeat.com/openapi.yaml # Cancel a payout request (https://docs.layerbeat.com/api/affiliates/cancelAffiliatePayout) ## POST /v1/affiliates/payouts/{id}/cancel Cancels a pending payout request and releases its reserved earnings. **Access:** User session: workspace owner. API keys aren't supported. ### Details - Requested or reviewed payouts can be canceled. Repeating cancellation is safe; already closed/rejected requests return `409`. Request and response schemas: https://layerbeat.com/openapi.yaml # Capture a referral visit (https://docs.layerbeat.com/api/affiliates/captureReferralVisit) ## POST /v1/referrals/visit Saves a referral code for a future signup. **Access:** Layerbeat browser origin. No sign-in required. ### Details - Returns `503 referrals_paused` while Refer & Earn is coming soon. - The first valid referral is kept in a secure cookie for 30 days. Invalid or suspended codes return `400`; this does not create an account or reward. Request and response schemas: https://layerbeat.com/openapi.yaml # Convert earnings into Layerbeat credit (https://docs.layerbeat.com/api/affiliates/convertAffiliateEarnings) ## POST /v1/affiliates/conversions Converts available referral earnings into the affiliate creator's personal credit. Keep the same `Idempotency-Key` when retrying. **Access:** Verified user session: workspace admin or owner. ### Details - Returns `503 referrals_paused` while Refer & Earn is coming soon. - Converted credit cannot be withdrawn or earn further commissions. Suspended referral accounts cannot convert earnings. Request and response schemas: https://layerbeat.com/openapi.yaml # Read affiliate dashboard (https://docs.layerbeat.com/api/affiliates/getAffiliateDashboard) ## GET /v1/affiliates Returns your workspace's referral account, earnings and program rules. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - A workspace without an activated account returns `account: null`. Request and response schemas: https://layerbeat.com/openapi.yaml # Read browser referral attribution (https://docs.layerbeat.com/api/affiliates/getReferralAttribution) ## GET /v1/referrals/attribution Returns the referral code saved in this browser, if it is still valid. **Access:** Public. No authentication required. ### Details - Missing, expired or suspended referrals return null fields. Customer identities are not included. Request and response schemas: https://layerbeat.com/openapi.yaml # List payout requests (https://docs.layerbeat.com/api/affiliates/listAffiliatePayouts) ## GET /v1/affiliates/payouts Lists your workspace's payout requests and reserved earnings. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Treasury transfers are not available yet. A reviewed request does not mean money has been sent. Request and response schemas: https://layerbeat.com/openapi.yaml # List private referrals (https://docs.layerbeat.com/api/affiliates/listAffiliateReferrals) ## GET /v1/affiliates/referrals Lists attributed referrals and their signup or first paid purchase dates. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Results are paginated and use anonymous referral IDs, without customer names, workspaces or servers. Request and response schemas: https://layerbeat.com/openapi.yaml # List purchase rewards (https://docs.layerbeat.com/api/affiliates/listAffiliateRewards) ## GET /v1/affiliates/rewards Lists rewards earned from eligible referred VPS purchases. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - The current program pays 5% on eligible charges for 12 months. Offers need at least 20% markup over positive recorded cost. - Rewards mature after 30 days and eligibility verification. The reward terms are saved when the charge settles. - Promotional/admin credit, failed provisioning and unresolved charges do not earn rewards. Request and response schemas: https://layerbeat.com/openapi.yaml # Read the earnings statement (https://docs.layerbeat.com/api/affiliates/listAffiliateStatement) ## GET /v1/affiliates/statement Lists your workspace's earnings history and adjustments. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Amounts are decimal USD values. Reversal deficits offset future earnings; use `next_cursor` for pagination. Request and response schemas: https://layerbeat.com/openapi.yaml # Reserve earnings for payout review (https://docs.layerbeat.com/api/affiliates/requestAffiliatePayout) ## POST /v1/affiliates/payouts Reserves affiliate cash earnings for a payout request. This does not send a blockchain transfer. **Access:** Verified owner session and approved affiliate partner. ### Details - Returns `503 referrals_paused` while Refer & Earn is coming soon. - Request at least $25 and supply a valid Solana wallet address and `Idempotency-Key`. Requests await manual review and treasury processing. Request and response schemas: https://layerbeat.com/openapi.yaml # Top up personal credit (https://docs.layerbeat.com/api/billing/createTopUp) ## POST /v1/billing/top-ups Creates a USDC or Rupiah top-up for your personal balance. Reuse the same `Idempotency-Key` if the request times out. **Access:** API key: `billing:write` · Session: any role, own account. ### Details - USDC funds USD credit. Doit requests use `currency: IDR` and whole Rupiah. Balances are not exchanged. - You can have at most 5 unpaid USDC top-ups at a time and start 20 in 24 hours; beyond that the request returns `409 quota_exceeded`. - For Doit, choose `payment_option` for QRIS or a supported virtual account, or omit it for hosted selection. Native checkout requires `Idempotency-Key`. - Use the exact USDC instructions or the original gateway checkout. Layerbeat covers processing fees. - A browser redirect is not proof of payment. Credit appears only after verification; an uncertain checkout returns `202`. - Refresh or replay the original payment instead of creating a replacement. API keys fund their creator's personal balance. - Default USD limits are $5–$1,000. Native IDR limits are configured separately. Partial, excess and late USDC receipts remain credit. - See the [top-up guides](https://docs.layerbeat.com/guides/money/) for each payment method. Request and response schemas: https://layerbeat.com/openapi.yaml # Get a payment (https://docs.layerbeat.com/api/billing/getPayment) ## GET /v1/billing/payments/{id} Returns the saved status and credited amount for a personal top-up. **Access:** API key: `billing:read` · Session: any role, own account. ### Details - This reads stored status without calling the gateway. Use refresh for a gateway check. Adding credit does not create a VPS. Request and response schemas: https://layerbeat.com/openapi.yaml # Get the wallet (https://docs.layerbeat.com/api/billing/getWallet) ## GET /v1/billing/wallet Returns your personal balance, reserved credit and available credit. **Access:** API key: `billing:read` · Session: any role, own account. ### Details - Available credit is the balance minus reservations. An API key reads its creator's wallet; changing workspaces does not change the wallet owner. Request and response schemas: https://layerbeat.com/openapi.yaml # List payment methods (https://docs.layerbeat.com/api/billing/listPaymentMethods) ## GET /v1/billing/payment-methods Lists enabled credit top-up methods and available QRIS or virtual-account options. **Access:** API key: `billing:read` · Session: any role, own account. ### Details - Solana appears first when enabled. Options apply to new payments; existing invoices keep their original method. - VPS purchases spend credit separately. Request and response schemas: https://layerbeat.com/openapi.yaml # List payments (https://docs.layerbeat.com/api/billing/listPayments) ## GET /v1/billing/payments Lists your personal USDC and Rupiah payments, newest first. **Access:** API key: `billing:read` · Session: any role, own account. Request and response schemas: https://layerbeat.com/openapi.yaml # List wallet transactions (https://docs.layerbeat.com/api/billing/listTransactions) ## GET /v1/billing/transactions Lists your personal credit transactions across workspaces, newest first. **Access:** API key: `billing:read` · Session: any role, own account. ### Details - A VPS purchase creates a `hold`, followed by a `charge` on success or `hold_release` on confirmed failure. - Charges are negative amounts. Hold entries show the size of the reservation. Request and response schemas: https://layerbeat.com/openapi.yaml # Use the payment network for a connected wallet (https://docs.layerbeat.com/api/billing/paymentSolanaRpc) ## POST /v1/billing/payments/{id}/solana-rpc Relays supported Solana RPC requests for your original USDC top-up. **Access:** API key: `billing:write` · Session: any role, own account. ### Details - Only documented RPC methods are accepted. A submitted transfer must match the payment's amount, mint, recipient and reference. - Submitting a transaction does not add credit until a finalized receipt is verified. - Browser requests need the Layerbeat origin and `X-CSRF-Token`. Request and response schemas: https://layerbeat.com/openapi.yaml # Receive a signed Doit payment notification (https://docs.layerbeat.com/api/billing/receiveDoitNotification) ## POST /v1/webhooks/doit Receives Doit payment updates and schedules payment verification. **Access:** Valid Doit webhook signature. ### Details - Signatures must match the raw body and a valid timestamp. Repeated events are safe; an event alone cannot add credit. - Refunds require manual review. Test and unknown signed events are acknowledged without changing balances. - Missing signing configuration returns `503`; authenticated payment checks remain available. Request and response schemas: https://layerbeat.com/openapi.yaml # Verify or recover a hosted IDR payment (https://docs.layerbeat.com/api/billing/refreshPayment) ## POST /v1/billing/payments/{id}/refresh Checks the payment provider for the status of your existing Doit top-up. **Access:** API key: `billing:write` · Session: any role, own account. ### Details - Reuses the original invoice and request identity, including after an uncertain checkout. Switching gateways does not replace pending payments. - A short cooldown limits repeated checks. Existing payments can settle while new top-ups are paused, but paused funding cannot create another checkout. - Other users receive `404`, including workspace owners. Request and response schemas: https://layerbeat.com/openapi.yaml # Pay an agent credit top-up with MPP on Tempo (https://docs.layerbeat.com/api/billing/topUpMpp) ## POST /v1/billing/top-ups/mpp Adds USD credit through a Machine Payments Protocol (MPP) charge paid in USDC.e on Tempo. Reuse the same request body and `Idempotency-Key` when sending the credential. **Access:** API key: `billing:write` · Session: any role, own account. ### Details - The first request returns `402` with a `WWW-Authenticate: Payment` challenge (`method="tempo"`, `intent="charge"`). The body repeats it with the decoded request. - Pay with one `transferWithMemo` of the exact amount to the recipient, carrying the MPP attribution memo for this challenge, then repeat this request with the credential in `Payment-Authorization`. Keep your API key in `Authorization`, as the challenge's `header` parameter says. - **Push:** your wallet broadcasts the transfer and the credential carries its hash. **Pull:** the credential carries the signed transaction and Layerbeat broadcasts it once. A pull transaction must make exactly that one call on this chain, pay its own fee (no sponsorship) and, if it sets an expiry, expire no later than the challenge. - `201` means a final transfer has credited the wallet, with a `Payment-Receipt`. `503 payment_not_final` means resend the same credential shortly. Never pay again. - A `402` with `error: payment_verification_failed` means the transaction does not pay this challenge: wrong amount, token, recipient or memo, or it failed. - API keys fund their creator. The account must be eligible for funding, and configured top-up limits apply. The small fractional amount that identifies the payment is kept as credit. - You can have at most 5 unpaid crypto top-ups at a time and start 20 in 24 hours; beyond that the request returns `409 quota_exceeded`. - mppx clients do all of this automatically. See the [agent payment guide](https://docs.layerbeat.com/guides/agent-payments/). Request and response schemas: https://layerbeat.com/openapi.yaml # Pay an agent credit top-up with x402 (https://docs.layerbeat.com/api/billing/topUpX402) ## POST /v1/billing/top-ups/x402 Adds USD credit through an x402 USDC payment on Solana. Reuse the same request body and `Idempotency-Key` when submitting payment. **Access:** API key: `billing:write` · Session: any role, own account. ### Details - The first request returns `402` with `PAYMENT-REQUIRED`. Authorize that exact payment, then repeat with `PAYMENT-SIGNATURE`. - `201` means finalized receipts have credited the wallet. `202` is still pending: poll the payment or replay this request. - API keys fund their creator. The account must be eligible for funding, and configured top-up limits apply. - The small fractional attribution amount is retained as credit. Use the offered network, USDC mint, fee payer and reference. - You can have at most 5 unpaid crypto top-ups at a time and start 20 in 24 hours; beyond that the request returns `409 quota_exceeded`. - Supports regular-wallet USDC transfers with the offered memo and bounded compute instructions. Smart wallets and address lookup tables are not supported. - If funding or verification is unavailable, new submissions return `503`. Check receipts before replacing an expired payment. - See the [agent payment guide](https://docs.layerbeat.com/guides/agents/) for the full flow. Request and response schemas: https://layerbeat.com/openapi.yaml # List images (https://docs.layerbeat.com/api/catalog/listImages) ## GET /v1/images Lists operating systems and applications available in a location. **Access:** Public. No authentication required. ### Details - Choose an image that fits your plan's RAM and disk. Images with `available: false` include a reason and cannot be purchased. - Results include versions and icon paths, and are cached for 60 seconds. Request and response schemas: https://layerbeat.com/openapi.yaml # List plans with prices (https://docs.layerbeat.com/api/catalog/listPlans) ## GET /v1/plans Lists VPS plans, specifications and prices for a location. **Access:** Public. No authentication required. ### Details - Monthly prices come from the one-month offer. Three- and twelve-month offers show their full prepaid totals. - Stock and quota are checked again before purchase. A catalog listing is not a stock reservation. - Results are cached for 60 seconds. Request and response schemas: https://layerbeat.com/openapi.yaml # List regions (https://docs.layerbeat.com/api/catalog/listRegions) ## GET /v1/regions Lists the locations where you can deploy a VPS. **Access:** Public. No authentication required. ### Details - Results are cached for 60 seconds. Request and response schemas: https://layerbeat.com/openapi.yaml # Attach a disk to a server (https://docs.layerbeat.com/api/disks/attachVolume) ## POST /v1/volumes/{id}/attach Attaches an available disk to a running server in the same zone, then mounts it at its mount folder. Returns an operation to track it. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - A new disk is formatted (ext4) the first time it is mounted. A disk that cannot be mounted automatically stays attached, unmounted, with a `note`; its data is never changed. - Different zones, a stopped server or a server at its disk limit return `400` or `409`. Request and response schemas: https://layerbeat.com/openapi.yaml # Buy a disk (https://docs.layerbeat.com/api/disks/createVolume) ## POST /v1/volumes Buys a Premium data disk with your personal credit, as its own bill with its own term and expiry, and returns an operation to track it. Keep the same `Idempotency-Key` when retrying. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Give `vm_id` to buy the disk for a server (it is created in the server's zone and attached and mounted at `/mnt/` once the server runs), or `region` and `zone` for an unattached disk. - Credit is reserved while the disk is created and charged once it exists. A confirmed failure releases the reservation; an uncertain result keeps it for review. - Insufficient credit returns `402`. Paused disk sales return `503 volumes_paused`; paused purchasing returns `503 purchases_paused`. - The disk keeps its data when detached or when its server ends, and can be attached to another server in the same zone. Request and response schemas: https://layerbeat.com/openapi.yaml # Delete a disk (https://docs.layerbeat.com/api/disks/deleteVolume) ## DELETE /v1/volumes/{id} Permanently deletes a detached disk and erases its data. Pass `confirm=`. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Detach the disk first; attached disks return `409`. Unused time is not refunded. Request and response schemas: https://layerbeat.com/openapi.yaml # Detach a disk from its server (https://docs.layerbeat.com/api/disks/detachVolume) ## POST /v1/volumes/{id}/detach Unmounts the disk inside the server (when it runs) and detaches it. The disk keeps its data and can be attached to another server in the same zone. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - A disk in use cannot be unmounted safely; the operation fails with `volume_busy` and the disk stays attached. Request and response schemas: https://layerbeat.com/openapi.yaml # Get a disk (https://docs.layerbeat.com/api/disks/getVolume) ## GET /v1/volumes/{id} Returns one disk: status, size, zone, attached server, mount folder, bill and expiry. **Access:** API key: `vm:read` · Session: any member. Request and response schemas: https://layerbeat.com/openapi.yaml # Disk options for a region (https://docs.layerbeat.com/api/disks/getVolumeOptions) ## GET /v1/volume-options Returns the disk sizes, terms, prices and zones you can buy in one region, with the servers in each zone a new disk could attach to. **Access:** API key: `vm:read` · Session: any member. ### Details - Disks attach only to servers in the same zone. Prices are per GB per month; a purchase is size × price × months, rounded up once. - Two disk types: `premium` (default) and `ssd` (faster, from 20 GB). Each has its own price, smallest size and zones. - `min_gb` is the smallest size sold: smaller disks are not offered. - `in_stock` is false while the region is sold out; a purchase then returns `409 out_of_stock`. - Regions without disks of the type return `404`. Request and response schemas: https://layerbeat.com/openapi.yaml # List disk prices (https://docs.layerbeat.com/api/disks/listDiskPrices) ## GET /v1/disk-prices Lists disk prices for every region and disk type on sale, as shown on the public disk pricing page. **Access:** Public. No authentication required. ### Details - A disk costs size × `price_per_gb_month` × months, rounded up once per order. Every term (`terms`) costs the same per month. - `min_gb` is the smallest size sold in that region; sizes go up in `step_gb` steps to `max_gb`. - `orderable` is false while disk purchases are paused; prices are still listed. Results are cached for 60 seconds. Request and response schemas: https://layerbeat.com/openapi.yaml # List system disks (https://docs.layerbeat.com/api/disks/listSystemDisks) ## GET /v1/system-disks Lists the main disk included with each active server: size, type and zone. A system disk is part of its server and billed with it; it cannot be detached or bought separately. **Access:** API key: `vm:read` · Session: any member. Request and response schemas: https://layerbeat.com/openapi.yaml # List disks (https://docs.layerbeat.com/api/disks/listVolumes) ## GET /v1/volumes Lists the workspace's disks, newest first. Deleted or released disks stay listed for 7 days. **Access:** API key: `vm:read` · Session: any member. Request and response schemas: https://layerbeat.com/openapi.yaml # Renew a disk (https://docs.layerbeat.com/api/disks/renewVolume) ## POST /v1/volumes/{id}/renew Extends a disk by 1, 3 or 12 months at the price per GB it was bought at, charging your personal credit. Keep the same `Idempotency-Key` when retrying. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Expired disks can be renewed for a short time before our provider erases them. - The renewal is sent to our provider once. A confirmed renewal is charged; a confirmed failure releases the reservation; an uncertain result keeps it for review. Request and response schemas: https://layerbeat.com/openapi.yaml # Rename a disk (https://docs.layerbeat.com/api/disks/updateVolume) ## PATCH /v1/volumes/{id} Changes a disk's display name. The mount folder chosen at purchase does not change. **Access:** API key: `vm:write` · Session: developer, admin or owner. Request and response schemas: https://layerbeat.com/openapi.yaml # Add a firewall rule (https://docs.layerbeat.com/api/network/addFirewallRule) ## POST /v1/vms/{id}/firewall-rules Adds an inbound firewall rule to the VPS. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - A VPS can have up to 100 rules. An identical rule returns `409 conflict`. The rule ID is derived from its protocol, port, CIDR and action. Request and response schemas: https://layerbeat.com/openapi.yaml # Delete a firewall rule (https://docs.layerbeat.com/api/network/deleteFirewallRule) ## DELETE /v1/vms/{id}/firewall-rules/{rule_id} Removes a firewall rule from the VPS. Removing the port 22 rule can block SSH access. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Use the server console if you lose SSH access. Request and response schemas: https://layerbeat.com/openapi.yaml # List firewall rules (https://docs.layerbeat.com/api/network/listFirewallRules) ## GET /v1/vms/{id}/firewall-rules Lists the VPS's current inbound firewall rules. **Access:** API key: `vm:read` · Session: any workspace role. ### Details - Traffic that does not match an `accept` rule is blocked. Request and response schemas: https://layerbeat.com/openapi.yaml # Get an operation (https://docs.layerbeat.com/api/operations/getOperation) ## GET /v1/operations/{id} Returns the progress and result of a VPS action. **Access:** API key: `vm:read` · Session: any workspace role. ### Details - Poll until `status` is `succeeded` or `failed`. `steps` show completed work and `error` explains a failure. - An `outcome_unknown` purchase may still have reserved credit. Follow the original operation rather than submitting another purchase. Request and response schemas: https://layerbeat.com/openapi.yaml # Add a member (https://docs.layerbeat.com/api/organization/addMember) ## POST /v1/org/members Adds an existing Layerbeat account to your workspace. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - The person must register and verify their email first. Unverified accounts return `409`. - Admins can add developers and viewers. Only owners can add admins or owners. Request and response schemas: https://layerbeat.com/openapi.yaml # Get the active organization (https://docs.layerbeat.com/api/organization/getOrg) ## GET /v1/org Returns your current workspace and, for user sessions, your role in it. **Access:** User session or API key. Request and response schemas: https://layerbeat.com/openapi.yaml # Read the audit log (https://docs.layerbeat.com/api/organization/listAuditLog) ## GET /v1/audit-log Lists workspace security and management events, newest first. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Includes sign-ins, key and member changes, VPS actions, console access and firewall changes. Request and response schemas: https://layerbeat.com/openapi.yaml # List members (https://docs.layerbeat.com/api/organization/listMembers) ## GET /v1/org/members Lists workspace members and their roles. **Access:** User session: workspace admin or owner. API keys aren't supported. Request and response schemas: https://layerbeat.com/openapi.yaml # Remove a member or leave (https://docs.layerbeat.com/api/organization/removeMember) ## DELETE /v1/org/members/{user_id} Removes a workspace member, or leaves the workspace when you select yourself. **Access:** User session. API keys aren't supported. ### Details - Removing someone else requires admin access for developers/viewers, or owner access for higher roles. - The removed member's keys are revoked. The last owner cannot leave. - A user who leaves their last workspace receives a new personal workspace. Request and response schemas: https://layerbeat.com/openapi.yaml # Change a member's role (https://docs.layerbeat.com/api/organization/updateMember) ## PATCH /v1/org/members/{user_id} Changes a workspace member's role. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Admins can change developers and viewers. Only owners can manage admin and owner roles. - The workspace must keep at least one owner. Request and response schemas: https://layerbeat.com/openapi.yaml # Liveness check (https://docs.layerbeat.com/api/platform/getHealth) ## GET /healthz Checks whether the API process is running. **Access:** Public. No authentication required. ### Details - Returns `ok`. This endpoint is not rate limited. Request and response schemas: https://layerbeat.com/openapi.yaml # Readiness check (https://docs.layerbeat.com/api/platform/getReady) ## GET /readyz Checks whether the API is ready to serve requests. **Access:** Public. No authentication required. ### Details - Returns `ready` when the database is reachable, or `503` when it is not. Use this for load-balancer health checks. Request and response schemas: https://layerbeat.com/openapi.yaml # Receive a signed email-provider delivery event (https://docs.layerbeat.com/api/platform/receiveEmailDeliveryEvent) ## POST /v1/webhooks/email Receives email delivery and bounce updates from Resend. **Access:** Valid Resend/Svix webhook signature. ### Details - Repeated events are safe. Delivery updates are matched to known messages and recipients. - This callback is unavailable when not configured (`404`). Request and response schemas: https://layerbeat.com/openapi.yaml # Price a server (https://docs.layerbeat.com/api/servers/createQuote) ## POST /v1/quotes Returns a VPS purchase price valid for 10 minutes. Pass its `id` as `quote_id` when purchasing. **Access:** API key: `vm:read` · Session: any workspace role. ### Details - A configuration that is not currently on sale returns `409 out_of_stock`. A quote does not reserve stock. Request and response schemas: https://layerbeat.com/openapi.yaml # Buy a server (https://docs.layerbeat.com/api/servers/createVm) ## POST /v1/vms Creates a VPS using your personal credit and returns an operation to track deployment. Keep the same `Idempotency-Key` when retrying. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Top up first. API-key purchases charge the key creator. Insufficient credit returns `402` without creating a server. - Credit is reserved while provisioning. Success charges it; a confirmed failure releases it. An uncertain result keeps the reservation for review. - Choose `ssh_key`, `custom_password` or `random_password`. Password modes do not require SSH keys. - Direct USDC payment is not supported here. Omit `payment_method` or use `wallet`. - New purchases return `503 purchases_paused` when purchasing is disabled. Already accepted requests can still be replayed. Request and response schemas: https://layerbeat.com/openapi.yaml # Delete a server (https://docs.layerbeat.com/api/servers/deleteVm) ## DELETE /v1/vms/{id} Permanently deletes a VPS and its data. Set `confirm` to the server name. No refund is currently issued. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Accepts `running`, `stopped` or `failed` servers. An unpaid `awaiting_payment` order is canceled instead. Request and response schemas: https://layerbeat.com/openapi.yaml # Forget the saved initial server password (https://docs.layerbeat.com/api/servers/forgetServerPassword) ## DELETE /v1/vms/{id}/password Removes Layerbeat's saved initial password. It does not change the password on the VPS. **Access:** Original purchaser with `vm:write`, or their API key. Sessions require developer access or higher. ### Details - The server must be ready. Repeating this request is safe; passwords cannot be forgotten during provisioning or an uncertain purchase. Request and response schemas: https://layerbeat.com/openapi.yaml # Get server metric access grants (https://docs.layerbeat.com/api/servers/getServerMetricAccess) ## GET /v1/vms/{id}/metrics/access Lists the members and API keys explicitly allowed to read this VPS's metrics. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Owner/admin sessions already have access. These grants apply only to metrics, not VPS management. Request and response schemas: https://layerbeat.com/openapi.yaml # Get server performance metrics (https://docs.layerbeat.com/api/servers/getServerMetrics) ## GET /v1/vms/{id}/metrics Returns CPU, memory, disk and network performance for the last 24 hours, sampled every five minutes. **Access:** `vm:read` and server metrics access. Owner/admin sessions have access; other members and API keys need a grant. ### Details - Select supported names with `metrics`. Readings can lag by at least two minutes and are cached for five minutes. - Missing readings stay empty; they are not replaced with zero. A latest reading older than five minutes is marked stale. - Memory percentage, memory used and disk percentage are separate measurements. They cannot be calculated from one another. - Servers without a metrics grant or outside your workspace return `404`. Provisioning/deletion returns `409`; unavailable readings return `503`. - Access is checked on every request, including cached readings. Do not cache responses in a browser or shared proxy. Request and response schemas: https://layerbeat.com/openapi.yaml # Get server traffic usage (https://docs.layerbeat.com/api/servers/getServerTraffic) ## GET /v1/vms/{id}/traffic Returns the VPS's used and remaining monthly traffic allowance. **Access:** API key: `vm:read` · Session: any workspace role. ### Details - Amounts are in bytes. Unmetered plans have `metered: false` and zero byte fields. - `overflow_bytes` shows usage beyond the allowance. `network_suspended` indicates suspension for an overdue account. - Values refresh about once a minute. Creation/deletion returns `409`; temporarily unavailable readings return `503`. Request and response schemas: https://layerbeat.com/openapi.yaml # Get a server (https://docs.layerbeat.com/api/servers/getVm) ## GET /v1/vms/{id} Returns a VPS's current status, public IP addresses and configuration. **Access:** API key: `vm:read` · Session: any workspace role. Request and response schemas: https://layerbeat.com/openapi.yaml # Read server renewal settings and prices (https://docs.layerbeat.com/api/servers/getVmRenewal) ## GET /v1/vms/{id}/renewal Returns renewal prices, automatic renewal settings and deadlines for this VPS. **Access:** API key: `vm:read` · Session: any workspace role. ### Details - Prices use the purchase-time lock where available, otherwise the published regular price. - Automatic renewal starts 48 hours before expiry. Purchased servers have an eight-day renewal grace period. - `deletion_at` closes the Layerbeat service when closure is enabled; it is not a physical infrastructure deletion schedule. - `can_manage` identifies the original purchaser. Deleted records cannot be renewed; imported servers without a purchaser have no automatic closure deadline. Request and response schemas: https://layerbeat.com/openapi.yaml # List servers (https://docs.layerbeat.com/api/servers/listVms) ## GET /v1/vms Lists the VPSs in your workspace. **Access:** API key: `vm:read` · Session: any workspace role. ### Details - Use `status=terminated` to see deleted-server history. Subscription closure ends Layerbeat access; it does not prove that infrastructure data has been erased. Request and response schemas: https://layerbeat.com/openapi.yaml # Open a browser console (https://docs.layerbeat.com/api/servers/openConsole) ## POST /v1/vms/{id}/console Returns a temporary link to the VPS console when you need access without SSH. Keep this link private. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - The link is a credential: do not share or log it. Responses are not cached, and console access is recorded in the audit log. Request and response schemas: https://layerbeat.com/openapi.yaml # Reboot a running server (https://docs.layerbeat.com/api/servers/rebootVm) ## POST /v1/vms/{id}/reboot Restarts a running VPS and returns an operation to track progress. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Other server states return `409 invalid_state`. The server shows `rebooting` until the operation finishes. Request and response schemas: https://layerbeat.com/openapi.yaml # Renew a server subscription (https://docs.layerbeat.com/api/servers/renewVm) ## POST /v1/vms/{id}/renew Renews a VPS for 1, 3 or 12 months using your personal credit. Keep the same `Idempotency-Key` when retrying. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - API keys charge their creator. `maximum_amount` is your spending limit. Purchase-time prices apply when a matching price is locked; otherwise the published regular price applies. - Poll the returned operation. A confirmed failure before submission releases credit; an uncertain submission keeps the reservation and blocks another renewal. - Purchased servers cannot start a renewal after the eight-day grace deadline. Imported servers without an original purchaser are exempt. - Paused renewals return `503 renewals_paused`. Request and response schemas: https://layerbeat.com/openapi.yaml # Replace server metric access grants (https://docs.layerbeat.com/api/servers/replaceServerMetricAccess) ## PUT /v1/vms/{id}/metrics/access Replaces the VPS's metrics access list. Send empty arrays to remove all explicit grants. **Access:** User session: workspace admin or owner. API keys aren't supported. ### Details - Both arrays are required, with at most 100 unique grants in total. - Members and active keys must belong to this workspace. Keys need `vm:read`; invalid targets return `404` and leave the old list unchanged. - Owner/admin session access is retained. Revocations apply to the next request, including cached readings. Request and response schemas: https://layerbeat.com/openapi.yaml # Reveal the initial generated server password (https://docs.layerbeat.com/api/servers/revealServerPassword) ## POST /v1/vms/{id}/password/reveal Shows the initial password for a VPS created with `random_password`. **Access:** Original purchaser with `vm:write`, or their API key. Sessions require developer access or higher. ### Details - Available for 24 hours after successful provisioning, or until forgotten. Custom passwords are never returned. - Repeated requests return the same password; this does not reset the server password. Other users receive `404`. Request and response schemas: https://layerbeat.com/openapi.yaml # Set opt-in automatic renewal (https://docs.layerbeat.com/api/servers/setVmRenewal) ## PUT /v1/vms/{id}/renewal Updates automatic renewal using the original purchaser's credit. Saving settings does not renew the VPS immediately. **Access:** Original purchaser with `vm:write`. Sessions require developer access or higher. ### Details - Choose a term, currency and spending limit. Only that currency's balance can be charged. - Attempts start 48 hours before expiry and may retry hourly within the eight-day grace period. Insufficient credit charges nothing. - Disabling consent cancels an automatic renewal that has not been submitted. An uncertain submitted renewal stays reserved for review. - The purchaser must remain eligible and have workspace write access. Imported servers without a purchasing user cannot opt in. Request and response schemas: https://layerbeat.com/openapi.yaml # Start a stopped server (https://docs.layerbeat.com/api/servers/startVm) ## POST /v1/vms/{id}/start Starts a stopped VPS and returns an operation to track progress. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Other server states return `409 invalid_state`. The server shows `starting` until the operation finishes. Request and response schemas: https://layerbeat.com/openapi.yaml # Stop a running server (https://docs.layerbeat.com/api/servers/stopVm) ## POST /v1/vms/{id}/stop Stops a running VPS and returns an operation to track progress. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - Other server states return `409 invalid_state`. The server shows `stopping` until the operation finishes. Request and response schemas: https://layerbeat.com/openapi.yaml # Add an SSH public key (https://docs.layerbeat.com/api/ssh-keys/addSshKey) ## POST /v1/ssh-keys Registers an SSH public key for use when creating a VPS. **Access:** API key: `ssh_key:write` · Session: developer, admin or owner. ### Details - Supports Ed25519, RSA, ECDSA and security-key types. Comments are removed; duplicate keys are rejected. Request and response schemas: https://layerbeat.com/openapi.yaml # Delete an SSH key (https://docs.layerbeat.com/api/ssh-keys/deleteSshKey) ## DELETE /v1/ssh-keys/{id} Removes an SSH key from your workspace. **Access:** API key: `ssh_key:write` · Session: developer, admin or owner. ### Details - Returns `409 invalid_state` while a server still references the key. This does not remove keys from existing servers. Request and response schemas: https://layerbeat.com/openapi.yaml # List SSH keys (https://docs.layerbeat.com/api/ssh-keys/listSshKeys) ## GET /v1/ssh-keys Lists SSH public keys registered in your workspace. **Access:** API key: `ssh_key:read` · Session: any workspace role. Request and response schemas: https://layerbeat.com/openapi.yaml # Check a deployment (https://docs.layerbeat.com/api/templates/checkDeployment) ## POST /v1/deployments/{id}/health Runs the template's read-only health check on the server. A passing check marks the deployment `ready`; a failing one marks it `failed` with the reason. **Access:** API key: `vm:write` · Session: developer, admin or owner. Request and response schemas: https://layerbeat.com/openapi.yaml # Deploy a template (https://docs.layerbeat.com/api/templates/createDeployment) ## POST /v1/deployments Installs a template on a running server without logging in to it, and returns an operation to track it. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - `confirm_ports` must list every port the template (and any template it needs) opens, as `443/tcp` or `443`; otherwise `400 ports_not_confirmed`. Only ports that were not already open are added, and removal closes only those. - Templates it needs (`requires`) that the server does not have are deployed first, in the same request, and returned in `dependencies`. - `inputs` are checked against the template's input types; unknown names are refused. Inputs reach the server as data, never as commands. - The server must run a supported system with enough memory and disk (`409 incompatible_server`). One deployment of a template per server; ports already used by another deployment and a change already running on the server return `409`. - A run whose result cannot be confirmed leaves the deployment `unknown`: run a health check, then retry with update. Paused templates return `503 templates_paused`. Request and response schemas: https://layerbeat.com/openapi.yaml # Get a deployment (https://docs.layerbeat.com/api/templates/getDeployment) ## GET /v1/deployments/{id} Returns one deployment: status, the address it reported, the end of its last output and the ports it opened. **Access:** API key: `vm:read` · Session: any member. Request and response schemas: https://layerbeat.com/openapi.yaml # Get a deployment's script (https://docs.layerbeat.com/api/templates/getDeploymentScript) ## GET /v1/deployments/{id}/script Returns the install script a deployment runs: the template's, or the edited one it was deployed with. **Access:** API key: `vm:read` · Session: any member. An edited script may contain secrets, so it is shown only to a signed-in workspace owner or admin, or the person who bought the server (`403` otherwise). Request and response schemas: https://layerbeat.com/openapi.yaml # Get a template (https://docs.layerbeat.com/api/templates/getTemplate) ## GET /v1/templates/{id} Returns one template with its README: what it installs, where its data lives and how to reach it. **Access:** Public. No authentication required. Request and response schemas: https://layerbeat.com/openapi.yaml # List deployments (https://docs.layerbeat.com/api/templates/listDeployments) ## GET /v1/deployments Lists the templates deployed on the workspace's servers. Removed deployments and deployments on deleted servers are left out. **Access:** API key: `vm:read` · Session: any member. Request and response schemas: https://layerbeat.com/openapi.yaml # List templates (https://docs.layerbeat.com/api/templates/listTemplates) ## GET /v1/templates Lists the templates you can deploy onto a running server: software made and reviewed by Layerbeat, such as Docker, coding agents and Supabase. **Access:** Public. No authentication required. ### Details - `ports` are opened on the server's firewall when you deploy, after you confirm them. - `inputs` are the values a deploy request takes; `requires` are templates deployed first when the server does not have them. - `os` lists the systems a template runs on: `linux` (every Linux image), `apt` (Ubuntu, Debian) or `rpm` (CentOS, Rocky Linux, OpenCloudOS). Results are cached for 60 seconds. Request and response schemas: https://layerbeat.com/openapi.yaml # Preview a template's script (https://docs.layerbeat.com/api/templates/previewTemplateScript) ## POST /v1/templates/{id}/script Returns exactly what an install would run on the server for these inputs: Layerbeat's short header (which passes your inputs as data and reports the result), then the template's install script, or your edited one. **Access:** Public. No authentication required. ### Details - Inputs given are checked against the template's input types; missing ones are left out of the preview. - `script` previews an edited install script (at most 24 KB). `customized` says whether it differs from the template's. While editing scripts is not available, an edited script returns `403`; the template's own script always previews. - Nothing is stored or run. The response is not cached. Request and response schemas: https://layerbeat.com/openapi.yaml # Remove a deployment (https://docs.layerbeat.com/api/templates/removeDeployment) ## DELETE /v1/deployments/{id} Uninstalls the template from the server and closes only the ports it opened. Data stays unless `delete_data=true`. **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - A template another deployment on the server needs (for example Docker under Supabase) returns `409`; remove the other one first. - The server must be running. Paused templates return `503 templates_paused`. Request and response schemas: https://layerbeat.com/openapi.yaml # Update or retry a deployment (https://docs.layerbeat.com/api/templates/updateDeployment) ## POST /v1/deployments/{id}/update Installs the template's latest version, or runs the install again after a failed or unconfirmed run (installs are safe to repeat). **Access:** API key: `vm:write` · Session: developer, admin or owner. ### Details - A version that opens new ports needs them in `confirm_ports` (`400 ports_not_confirmed`). - A deployment already on the latest version returns `409`. Templates it needs must be ready on the server. - A deployment with an edited script cannot be retried while editing scripts is not available (`403`). Request and response schemas: https://layerbeat.com/openapi.yaml # Agents and MCP (https://docs.layerbeat.com/cli/agents) `layerbeat mcp serve` turns the CLI into a [Model Context Protocol](https://modelcontextprotocol.io) server. Your coding agent then sees Layerbeat as tools — list servers, open a port, run a command, deploy a template — and uses them when you ask in plain words: *"restart agent-01"*, *"open port 443 on the API server"*, *"how much disk is left?"*. ## 1. Install and give the agent a key [#1-install-and-give-the-agent-a-key] [Install the CLI](/cli/install), then create an API key just for the agent, so its actions show under its own name and it can do only what you allow: ```bash layerbeat keys create claude-code --scope vm:read --scope vm:write ``` You can also skip the key and let the agent use your own sign-in from `layerbeat login`. A key is the safer choice. ## 2. Add Layerbeat to your agent [#2-add-layerbeat-to-your-agent] **Claude Code** ```bash claude mcp add layerbeat -e LAYERBEAT_API_KEY=lb_live_... -- layerbeat mcp serve ``` **Codex** ```bash codex mcp add layerbeat --env LAYERBEAT_API_KEY=lb_live_... -- layerbeat mcp serve ``` **Cursor** — `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (everywhere): ```json { "mcpServers": { "layerbeat": { "command": "layerbeat", "args": ["mcp", "serve"], "env": { "LAYERBEAT_API_KEY": "lb_live_..." } } } } ``` **opencode** — `opencode.json`: ```json { "mcp": { "layerbeat": { "type": "local", "command": ["layerbeat", "mcp", "serve"], "environment": { "LAYERBEAT_API_KEY": "lb_live_..." } } } } ``` Any other MCP client: run `layerbeat mcp serve` as a local (stdio) server. Leave out the key setting to use your own sign-in. ## 3. Ask it to work [#3-ask-it-to-work] The Canvas in the console shows the agent's changes on each server's activity, under the key's name. ## What the agent can do [#what-the-agent-can-do] By default the agent can **read** your workspace and **manage existing servers**, but cannot spend or delete: | Tools | Available | | --- | --- | | `whoami`, `list_regions`, `list_plans`, `list_images`, `quote`, `credit` | Always | | `list_servers`, `get_server`, `get_operation`, `server_metrics`, `server_traffic` | Always | | `start_server`, `stop_server`, `reboot_server` | Always | | `list_firewall_rules`, `add_firewall_rule`, `remove_firewall_rule`, `list_ssh_keys` | Always | | `run_command` (over SSH, with the server's pinned host key) | Always | | `volume_options`, `list_volumes`, `attach_volume`, `detach_volume` | Always | | `list_templates`, `get_template`, `template_script`, `list_deployments`, `get_deployment`, `deploy_template`, `check_deployment`, `update_deployment`, `remove_deployment` | Always | | `create_server`, `renew_server`, `create_volume`, `renew_volume`, `top_up` | With `--allow-spend` | | `delete_server`, `delete_volume`, `remove_deployment_and_data` | With `--allow-delete` | To let the agent buy, start it with `layerbeat mcp serve --allow-spend` in the configuration above. Every purchase then still needs a maximum price and an idempotency key, so an agent can't overspend or buy twice by retrying. The tools also need the key's scopes: buying needs `vm:write`, top-ups `billing:write`. `top_up` returns payment instructions for a person to pay. With `pay` set to `x402` or `mpp`, the agent pays it right away from this computer's wallet through pay or mppx, exactly like [`layerbeat topup --pay`](/cli/credit#let-an-agent-pay). Only agree to an amount you are happy for it to spend. ## Agents without MCP [#agents-without-mcp] An agent that runs shell commands can use the CLI directly. Use `--json` and `--no-input`, add `--yes` to purchases it is allowed to make, and check exit codes; see [Scripting](/cli/scripting). The MCP tools above add `--yes` themselves, because they already require `--allow-spend`, a maximum price and an idempotency key. For agents that call the HTTP API and pay with x402 or MPP, see [Agent payments](/guides/agent-payments). # Credit (https://docs.layerbeat.com/cli/credit) Servers, disks and renewals are paid in advance from your **personal credit**. You have separate USD and IDR balances; a purchase uses one of them and they are never combined or converted. See [Credit and billing](/guides/money). ```bash layerbeat credit # your balances, and what is held for orders in progress layerbeat transactions # top-ups, purchases, renewals, holds and refunds layerbeat transactions --all # every page ``` ## Add credit [#add-credit] ```bash layerbeat payment-methods # what you can pay with right now layerbeat topup 25 # USD with USDC on Solana (the default) layerbeat topup 400000 --method doit --payment-option qris # IDR with QRIS layerbeat topup 400000 --method doit --payment-option va:bca # IDR by bank transfer ``` `topup` prints exact payment instructions: the address and amount to send, or the QRIS code or account number to pay. Credit is added once the payment is confirmed: ```bash layerbeat payments # your top-ups layerbeat payment pay_... # one top-up layerbeat payment pay_... --refresh # ask the payment provider again ``` Top-ups started with an API key need the `billing:write` scope and add to the personal credit of the key's creator. ## Let an agent pay [#let-an-agent-pay] With `--pay`, the top-up is paid right away from an agent wallet on this computer, instead of printing instructions: ```bash layerbeat topup 25 --pay x402 --yes # USDC on Solana, paid with pay (pay.sh) layerbeat topup 25 --pay mpp --yes # USDC.e on Tempo, paid with mppx ``` Install the payer first: `brew install pay` then `pay setup`, or `npm install -g mppx` with a Tempo wallet (`mppx account create`, or `MPPX_PRIVATE_KEY`). Use `--payer PATH` if it isn't on your `PATH`. - **Your key stays in the CLI.** The payer never receives your Layerbeat key. It talks to a one-time relay on `127.0.0.1`, which adds the key inside the CLI and forwards only this top-up. - **The amount is capped.** Before any wallet is involved, the CLI reads the offer and refuses one above the amount you asked for, plus the identifying suffix of under one cent. - **It asks first.** In a terminal it asks before paying. Scripts and agents pass `--yes`. - **It never pays twice.** Rerun with the same `--idempotency-key` to check on a payment that is still confirming. The command waits for the payment to be confirmed, then prints it. See [Agent payments](/guides/agent-payments) for the protocols and for paying from your own code. # Disks and firewall (https://docs.layerbeat.com/cli/disks-and-firewall) ## Disks [#disks] A disk is extra storage with its own prepaid term. It keeps its data when it is detached or its server ends, and can move to another server in the same zone. See [Disks](/guides/disks) for prices and rules. ```bash layerbeat volume prices --region sgp # public prices, no sign-in layerbeat volume options --region sgp # sizes, steps, terms and zones layerbeat volume new data --server agent-01 --size 50 --max-price 5 --wait ``` Buying or renewing a disk asks for a yes in a terminal; scripts add `--yes`. With `--server` the disk is created in that server's zone, attached and mounted at `/mnt/data` (Windows: `C:\mnt\data`). Without a server, give `--region` and `--zone` to buy an unattached disk. ```bash layerbeat volume ls layerbeat volume get data layerbeat volume detach data --wait # unmounts first; data is kept layerbeat volume attach data agent-02 --wait # same zone only layerbeat volume rename data postgres-data layerbeat volume renew data --term 3 --max-price 15 layerbeat volume rm data --confirm data # deletes the disk and its data layerbeat volume system-disks # each server's own disk, included in its price ``` ## Firewall [#firewall] Each server has its own firewall in front of it. New servers start with the usual rules for SSH, web traffic and ping; `layerbeat fw ls` shows exactly what is open. ```bash layerbeat fw ls agent-01 layerbeat fw add agent-01 --port 8080 layerbeat fw add agent-01 --port 5432 --cidr 203.0.113.7/32 --description "office" layerbeat fw add agent-01 --port 3000-3100 --protocol udp layerbeat fw rm agent-01 fw_... ``` | Flag | Default | Meaning | | --- | --- | --- | | `--port` | | A port or range, for example `443` or `8000-8100` (not for `icmp`) | | `--protocol` | `tcp` | `tcp`, `udp`, `icmp` or `all` | | `--cidr` | `0.0.0.0/0` | Who may connect | | `--action` | `accept` | `accept` or `drop` | See [Networking](/guides/networking). # Command-line tool (https://docs.layerbeat.com/cli) `layerbeat` is Layerbeat's command-line tool (`lb` for short). It does everything the console does — servers, SSH, disks, firewall, templates, credit — and gives coding agents like Claude Code, Codex, Cursor and opencode the same abilities through MCP. ## Get started in a minute [#get-started-in-a-minute] ```bash curl -fsSL https://layerbeat.com/install.sh | sh layerbeat login layerbeat new ``` 1. **Install.** The installer puts `layerbeat` and `lb` in `~/.local/bin` on macOS or Linux, after checking the download's checksum. See [Install and update](/cli/install). 2. **Sign in.** `layerbeat login` opens the console in your browser; approve the request and you're signed in for 30 days from your last use. See [Sign in](/cli/sign-in). 3. **Create a server.** `layerbeat new` asks for a name, location, plan, image and login, shows the exact total and buys only after you confirm. See [Servers](/cli/servers). Then connect to it: ```bash layerbeat ssh agent-01 ``` You need a Layerbeat account with credit. Create the account at [layerbeat.com](https://layerbeat.com) and add credit from the console or with [`layerbeat topup`](/cli/credit). ## What you can do [#what-you-can-do] Price, buy, start, stop, renew and delete servers. Log in, run commands and copy files with pinned host keys. Add storage that moves between servers; open and close ports. Install Claude Code, Codex, Docker, Supabase and more without SSH. Check your balance, top up and see your history. Let your coding agent manage Layerbeat as tools. JSON output, exit codes and safe retries. Every command on one page. ## How it works [#how-it-works] The CLI calls Layerbeat's [public API](/api) with your sign-in or an API key, so everything it does follows the same rules as the console: your workspace and role, your own credit, and the same audit log. Names work wherever an ID does (`agent-01` or `vm_…`); when a name matches more than one thing, the CLI lists the choices instead of guessing. Run `layerbeat --help` or `layerbeat COMMAND --help` for the exact options of any command. # Install and update (https://docs.layerbeat.com/cli/install) ## Install [#install] ```bash curl -fsSL https://layerbeat.com/install.sh | sh ``` The installer: - picks the build for your system: macOS (Apple silicon or Intel) or Linux (x86-64 or ARM64; a static build that runs on any distribution, Alpine included); - downloads it from `layerbeat.com` over HTTPS and checks it against the published SHA-256 checksums — **nothing is installed if the check fails**; - installs `layerbeat` in `~/.local/bin`, with `lb` as a short alias; - tells you if `~/.local/bin` is not on your `PATH`, and how to add it. No `curl`? `wget -qO- https://layerbeat.com/install.sh | sh` works the same way. Check it worked: ```bash layerbeat --version layerbeat status # is the Layerbeat API reachable? ``` ### Options [#options] Set these before `sh`: | Variable | Effect | | --- | --- | | `LAYERBEAT_INSTALL_DIR` | Install somewhere else, for example `~/bin` or `/usr/local/bin` | | `LAYERBEAT_VERSION` | Install a specific version instead of the latest, for example `1.0.0` | ```bash curl -fsSL https://layerbeat.com/install.sh | LAYERBEAT_INSTALL_DIR=/usr/local/bin sh ``` ### Read it first [#read-it-first] The script is short and readable. To look before running it: ```bash curl -fsSL https://layerbeat.com/install.sh -o install.sh less install.sh sh install.sh ``` ### Windows [#windows] Use the Linux build inside [WSL](https://learn.microsoft.com/windows/wsl/install): open your WSL terminal and run the same command. ## Update [#update] Run the installer again. It replaces the binary in place and keeps your sign-in and settings. ```bash curl -fsSL https://layerbeat.com/install.sh | sh ``` ## Shell completion [#shell-completion] ```bash # zsh mkdir -p ~/.zfunc && layerbeat completion zsh > ~/.zfunc/_layerbeat # bash layerbeat completion bash > ~/.local/share/bash-completion/completions/layerbeat # fish layerbeat completion fish > ~/.config/fish/completions/layerbeat.fish ``` For zsh, make sure `~/.zfunc` is on your `fpath` before `compinit` in `~/.zshrc`. ## Where files go [#where-files-go] | Path | What | | --- | --- | | `~/.local/bin/layerbeat`, `~/.local/bin/lb` | The program and its alias | | `~/.config/layerbeat/config.json` | Your saved sign-in and settings, readable only by you | | `~/.config/layerbeat/known_hosts` | Your servers' pinned SSH host keys | `XDG_CONFIG_HOME` moves the configuration folder. ## Uninstall [#uninstall] ```bash layerbeat logout # end the session on Layerbeat's side rm ~/.local/bin/layerbeat ~/.local/bin/lb rm -r ~/.config/layerbeat # forget saved settings and host keys ``` # Command reference (https://docs.layerbeat.com/cli/reference) Run `layerbeat COMMAND --help` for every option of a command. `lb` works in place of `layerbeat` everywhere. ## Options for every command [#options-for-every-command] | Option | Meaning | | --- | --- | | `--json` | Print JSON (the API's own response shapes). The default when stdout is not a terminal | | `--no-input` | Never prompt; fail instead | | `--yes`, `-y` | Answer yes to purchase confirmations (scripts and agents). Without it, buying or renewing asks in a terminal and is refused elsewhere | | `--workspace ORG_ID` | Act on this workspace (signed-in sessions only) | | `--api-url URL` | Use another Layerbeat API instead of `https://layerbeat.com` (also `LAYERBEAT_API_URL`). Must be `https://`; `http://` only for `localhost`, `127.0.0.1` or `[::1]` | | `-h`, `--help` / `-V`, `--version` | Help and version | ## Account and sign-in [#account-and-sign-in] | Command | What it does | | --- | --- | | `login` | Sign in through your browser (`--no-browser` over SSH); or save an API key piped on stdin | | `logout` | Sign out and forget the saved token | | `whoami` | You, your workspace, permissions and credit | | `doctor` | Check configuration, connection and sign-in | | `status` | Check that the Layerbeat API is up | | `sessions ls` / `rm` | Your signed-in browsers and CLIs | | `keys ls` / `create` / `rm` | API keys for scripts and agents (signed-in sessions only) | | `account …` | Setup, currency, email, password and connected Google or GitHub sign-ins | | `notifications show` / `set` / `history` | Which emails you receive | | `org show` / `members` / `add-member` / `set-role` / `remove-member` / `audit` | Your workspace, its members and audit log | | `signup` | Create an account (not on layerbeat.com, which needs the browser check) | ## Catalog [#catalog] | Command | What it does | | --- | --- | | `regions` | Locations | | `plans [--region R] [--family general\|fast] [--os linux\|windows]` | Configurations, with their system, prices and stock for a region | | `images [--region R] [--all]` | Operating systems and applications | | `quote --region R --plan P --image I [--term N]` | The exact total for a server | ## Servers [#servers] | Command | What it does | | --- | --- | | `new [NAME]` | Buy a server: asks in a terminal (OS or app, then the plans that fit it, term, login, then a yes), or takes flags (`--os`, `--max-price`, `--idempotency-key`, `--yes`, `--wait`…) | | `ls` / `get SERVER` | List servers / show one | | `start` / `stop` / `reboot SERVER` | Power (`--wait` to wait) | | `rm SERVER --confirm NAME` | Delete permanently | | `renew SERVER --max-price AMOUNT` | Extend the prepaid term | | `renewal show` / `set SERVER` | Renewal prices and automatic renewal | | `metrics SERVER` / `traffic SERVER` | Usage in the last 24 hours / this month's transfer | | `metrics-access show` / `set SERVER` | Who may see a server's metrics | | `password reveal` / `forget SERVER` | The first-login password | | `console SERVER` | Open the browser console | | `operation OP` / `wait OP` | Show or wait for an operation | ## Access [#access] | Command | What it does | | --- | --- | | `ssh SERVER [-- COMMAND]` | SSH in, or run one command | | `exec SERVER -- COMMAND` | Run a command without prompts; its exit status becomes the CLI's | | `cp FROM TO` | Copy files; `server:path` on either side, `-r` for folders | | `ssh-key ls` / `add NAME` / `rm` | Your SSH public keys | ## Disks and firewall [#disks-and-firewall] | Command | What it does | | --- | --- | | `volume prices` / `options` | Public disk prices / sizes, terms and zones | | `volume new NAME --size GB [--server S]` | Buy a disk, attached and mounted, or unattached in a zone | | `volume ls` / `get` / `system-disks` | Your disks / one disk / servers' own disks | | `volume attach VOL SERVER` / `detach VOL` | Move a disk between servers in a zone | | `volume rename` / `renew` / `rm --confirm` | Rename, extend or delete a disk | | `fw ls` / `add` / `rm SERVER` | A server's firewall rules | ## Templates [#templates] | Command | What it does | | --- | --- | | `template ls` / `show T` | The catalog / one template | | `template deploy T --server S` | Install it (`--input`, `--ports` or `--accept-ports`, `--wait`) | | `template deployments` / `status D` | What is deployed where / one deployment | | `template check` / `update` / `rm D` | Health check, update or retry, remove (`--delete-data`) | | `template script T\|D` | The exact script that runs on the server | ## Credit [#credit] | Command | What it does | | --- | --- | | `credit` | Your USD and IDR balances | | `transactions` | Credit history | | `payment-methods` | What you can pay with | | `topup AMOUNT [--method M]` | Add credit; prints payment instructions | | `topup AMOUNT --pay x402\|mpp [--payer PATH]` | An agent pays now from its own wallet ([how](/cli/credit#let-an-agent-pay)) | | `payments` / `payment ID [--refresh]` | Your top-ups | | `affiliate …` | Referral and partner program | ## Agents and tools [#agents-and-tools] | Command | What it does | | --- | --- | | `mcp serve [--allow-spend] [--allow-delete]` | Layerbeat as MCP tools for coding agents | | `api METHOD PATH [-d JSON] [-H HEADER]` | Call any API endpoint | | `completion SHELL` | Shell completions for bash, zsh, fish, elvish or PowerShell | ## Environment [#environment] | Variable | Meaning | | --- | --- | | `LAYERBEAT_API_KEY` | Use this API key (wins over a saved sign-in) | | `LAYERBEAT_API_URL` | Use another Layerbeat API (same rules as `--api-url`) | | `XDG_CONFIG_HOME` | Where the `layerbeat` settings folder lives (default `~/.config`) | # Scripting (https://docs.layerbeat.com/cli/scripting) ## Output [#output] When stdout is not a terminal — in a pipe, a script or an agent — the CLI prints JSON: the API's own response shapes. In a terminal it prints tables; add `--json` to get JSON there too. ```bash layerbeat ls --json | jq -r '.data[] | select(.status == "running") | .name' layerbeat ls -q # names only, one per line ``` Errors go to **stderr**, as JSON when stdout is not a terminal, and leave stdout empty. ## Never prompt [#never-prompt] `--no-input` makes any command fail instead of asking a question. Without a terminal the CLI never prompts anyway: `layerbeat new` with a missing flag is an error, not a question. ## Saying yes to purchases [#saying-yes-to-purchases] Buying or renewing a server or a disk spends credit, so it needs a yes. In a terminal the CLI shows the order and asks. In a script or agent, pass `--yes` (`-y`). Without it, the command exits 2 with `confirmation_required` and nothing is bought. ## Exit codes [#exit-codes] | Code | Meaning | | --- | --- | | 0 | Success | | 2 | Usage error (a missing or wrong flag), or a purchase without `--yes` and without a terminal (`confirmation_required`) | | 3 | Not signed in, or the key lacks the permission | | 4 | Not found | | 5 | Invalid state: the server is busy, already in that state, or the change conflicts | | 6 | Not enough credit, or the total is above your `--max-price` | | 7 | Rate limited: wait and try again | | 8 | `--wait` timed out (the operation may still finish; check it with `layerbeat operation`) | | 9 | Layerbeat or the network is unavailable | | 10 | Out of stock, or a quota is reached | Don't retry 2, 3, 4, 6 or 10 without changing something; back off before retrying 7 and 9. ## Waiting [#waiting] Changes run as **operations**. By default a command returns as soon as the change is accepted, with an `op_...` ID. Then: ```bash layerbeat start agent-01 --wait # wait inside the command layerbeat wait op_... --timeout 900 # or wait later layerbeat operation op_... # check without waiting ``` See [Asynchronous operations](/guides/asynchronous-operations). ## Safe retries [#safe-retries] Buying (`new`, `renew`, `volume new`, `volume renew`, `topup`) takes an `--idempotency-key`. The same key never charges twice, so a script that times out or crashes can simply run the same command again with the same key: ```bash KEY=deploy-$(date +%Y%m%d)-agent-01 layerbeat new agent-01 --region sgp --plan SG-B224 --image "Ubuntu 24.04" \ --ssh-key ci --max-price 5 --idempotency-key "$KEY" --no-input --yes --wait ``` Always pass `--max-price` in automation: the command refuses a total above it, whatever the price is when it runs. See [Safe retries](/guides/idempotency). ## Any API call [#any-api-call] `layerbeat api` calls any endpoint with your sign-in or key, for anything without its own command: ```bash layerbeat api GET /v1/billing/wallet layerbeat api POST /v1/vms/vm_.../firewall-rules -d '{"protocol":"tcp","port":"8080"}' layerbeat api POST /v1/vms -d @order.json -H "Idempotency-Key: $KEY" ``` `-d` takes JSON, `@file` or `-` for stdin. The [API reference](/api) lists every endpoint. ## In CI [#in-ci] ```yaml # GitHub Actions - run: curl -fsSL https://layerbeat.com/install.sh | sh - run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" - run: layerbeat template update https-proxy --server web-1 --wait env: LAYERBEAT_API_KEY: ${{ secrets.LAYERBEAT_API_KEY }} ``` `layerbeat ssh`, `exec` and `cp` also need an SSH private key that the server accepts, available to the job. # Servers (https://docs.layerbeat.com/cli/servers) ## Choose [#choose] ```bash layerbeat regions layerbeat plans --region sgp # prices and stock in Singapore layerbeat plans --region sgp --family fast layerbeat images --region sgp ``` These work without signing in. Plans and images accept a name or an ID: `SG-B224` or `bv-sgp-…`, `"Ubuntu 24.04"` or `ubuntu-24-04`. ## Price [#price] ```bash layerbeat quote --region sgp --plan SG-B224 --image "Ubuntu 24.04" --term 3 ``` `--term` is 1, 3 or 12 months; `--currency USD` or `IDR` picks the balance to pay from (default: your preference). See [Pricing](/guides/pricing) for how prices work. ## Buy [#buy] In a terminal, just run: ```bash layerbeat new ``` It asks for everything it needs: - a name and location; - the **operating system or application**, grouped as Linux, Windows Server and applications, each with its lowest monthly price; - a plan, from a table of only the plans that fit that choice (Windows plans for Windows Server, with enough disk); - a term, and how you'll log in. It then shows the order and the exact total, and buys only after you answer `y`. In a script, or to skip the questions, pass the choices as flags. Every purchase needs a yes: in a terminal the CLI shows the order and asks. Scripts and agents add `--yes`; without it, and without a terminal, nothing is bought (exit 2, `confirmation_required`). ```bash layerbeat new agent-01 \ --region sgp --plan SG-B224 --image "Ubuntu 24.04" \ --ssh-key laptop \ --max-price 5 \ --yes --wait ``` | Flag | Meaning | | --- | --- | | `--ssh-key NAME` | Install this SSH key (repeatable). Add keys with `layerbeat ssh-key add laptop` (reads `~/.ssh/id_ed25519.pub`) | | `--password random` | Log in with a generated password instead; read it once with `layerbeat password reveal agent-01`. `custom` asks for your own, hidden | | `--os linux\|windows` | Only offer this system's images and plans. Otherwise it follows from `--image` or `--plan` | | `--max-price AMOUNT` | Refuse to buy if the quoted total is higher | | `--yes`, `-y` | Buy without asking (scripts and agents) | | `--term 1\|3\|12` | Prepaid months | | `--auto-renew` | Renew automatically from your credit before it expires | | `--tag KEY=VALUE` | A label (repeatable) | | `--idempotency-key KEY` | Retry safely: the same key never buys twice. See [Scripting](/cli/scripting#safe-retries) | | `--dry-run` | Show the price and stop | | `--wait` | Wait until the server is running | ### Windows [#windows] Windows servers have their own plans (`layerbeat plans --region sgp --os windows`) and log in as `Administrator` over Remote Desktop with a password, never SSH keys: ```bash layerbeat new win-01 --region sgp --plan SG-W225 --image "Windows Server 2022" \ --password random --max-price 8 --yes --wait layerbeat password reveal win-01 # once it is running ``` A Windows image on a Linux plan, or `--ssh-key` with Windows, is refused before anything is priced. See [Windows servers](/guides/windows). ## See [#see] ```bash layerbeat ls # your servers layerbeat ls -q # names only, one per line layerbeat get agent-01 # one server: status, IP, plan, expiry layerbeat metrics agent-01 # CPU, memory, disk and network, last 24 hours layerbeat traffic agent-01 # this month's transfer ``` ## Power [#power] ```bash layerbeat stop agent-01 --wait layerbeat start agent-01 --wait layerbeat reboot agent-01 layerbeat console agent-01 # open the browser console ``` Every change is an operation. Without `--wait` the command returns at once with an operation ID; follow it with `layerbeat wait op_...`. ## Renew [#renew] ```bash layerbeat renewal show agent-01 # when it expires, and renewal prices layerbeat renew agent-01 --term 3 --max-price 15 layerbeat renewal set agent-01 --auto-renew on --max-price 5 ``` Renewing asks for a yes in a terminal; scripts add `--yes`. A server bought at a launch price renews at that price. See [Renewals](/guides/renewals). ## Delete [#delete] ```bash layerbeat rm agent-01 --confirm agent-01 ``` Deleting is permanent and the remaining term is not refunded. `--confirm` must repeat the server's name. ## Passwords [#passwords] ```bash layerbeat password reveal agent-01 # only the buyer, while it is kept layerbeat password forget agent-01 # delete the stored copy now ``` # Sign in (https://docs.layerbeat.com/cli/sign-in) ## Sign in through your browser [#sign-in-through-your-browser] ```bash layerbeat login ``` The console opens in your browser and asks you to approve **layerbeat on _your computer_**. Approve it and the CLI is signed in. The sign-in lasts 30 days from its last use, so a CLI you use regularly stays signed in. **Over SSH, or on a machine without a browser**, use `--no-browser`. The CLI prints a link; open it on any device where you're signed in to Layerbeat, approve, and paste the code the console shows (it starts with `lb_cli_`): ```bash layerbeat login --no-browser ``` Check who you are: ```bash layerbeat whoami # you, your workspace, your role and your credit layerbeat doctor # configuration, connection and sign-in, checked one by one ``` New to Layerbeat? Create your account at [layerbeat.com](https://layerbeat.com) first. `layerbeat signup` and `layerbeat login --email` don't work on layerbeat.com, which needs the browser's security check. ## API keys for scripts and agents [#api-keys-for-scripts-and-agents] A script or an agent should use its own **API key**, not your sign-in. Its changes then show under its own name in the audit log and on the Canvas, it gets only the permissions you give it, and you can revoke it on its own. Create one in the console under **Access & keys**, or from a signed-in CLI: ```bash layerbeat keys create deploy-bot --scope vm:read --scope vm:write ``` The key is printed once, on stdout. Then either set it in the environment: ```bash export LAYERBEAT_API_KEY=lb_live_... ``` or save it, by piping it in (it never appears in your shell history): ```bash printf %s "$KEY" | layerbeat login ``` | Scope | Allows | | --- | --- | | `vm:read` | See servers, disks, templates, firewall rules, metrics and operations | | `vm:write` | Power, firewall, disks, templates and buying servers | | `ssh_key:read`, `ssh_key:write` | See or change your SSH keys | | `billing:read`, `billing:write` | See credit and history; start top-ups | Purchases made with a key are paid from the personal credit of the person who created it. Keys belong to the workspace where they were created and can't manage other keys or sessions. `layerbeat keys ls` lists them; `layerbeat keys rm KEY_ID` revokes one. `LAYERBEAT_API_KEY` always wins over a saved sign-in, and `layerbeat doctor` tells you which one is in use. ## Workspaces [#workspaces] A signed-in session can act on any workspace you belong to. Pick one with `--workspace`: ```bash layerbeat ls --workspace org_... ``` An API key always acts on the workspace it was created in. ## Sessions and signing out [#sessions-and-signing-out] ```bash layerbeat sessions ls # browsers and CLIs signed in as you layerbeat sessions rm sess_... # sign one out layerbeat logout # sign out this CLI and forget the saved token ``` ## Another API [#another-api] The CLI talks to `https://layerbeat.com` unless you tell it otherwise; you don't need to set anything. To use another Layerbeat API, such as a local development server, pass `--api-url` or set `LAYERBEAT_API_URL`; `layerbeat login --save-api-url URL` makes it the default. Because your sign-in is sent to that address, it must use `https://`. Unencrypted `http://` is accepted only for this computer itself (`localhost`, `127.0.0.1` or `[::1]`), and an address with a user name in it (`https://user@host`) is refused. # SSH, exec and copy (https://docs.layerbeat.com/cli/ssh) These commands use your computer's OpenSSH, with the server's address and user filled in for you. ```bash layerbeat ssh agent-01 # an interactive shell layerbeat ssh agent-01 -- uptime # one command layerbeat exec agent-01 -- df -h / # one command, never prompts (for scripts and agents) layerbeat cp ./app.tar agent-01:/root/ # copy to the server layerbeat cp agent-01:/var/log/syslog . # copy from the server layerbeat cp -r ./site agent-01:/srv/ # a folder ``` ## Host keys are pinned [#host-keys-are-pinned] When Layerbeat sets up a server it records the server's SSH host keys. The CLI checks every connection against them and refuses a server that presents a different key — so you never have to answer "Are you sure you want to continue connecting?", and an agent never trusts an unknown machine. The keys are kept in `~/.config/layerbeat/known_hosts`. A server set up before host keys were recorded has none on file. For those, `--accept-new-host-key` (on `exec` and `cp`) trusts the first key it sees and pins it from then on. ## exec for scripts and agents [#exec-for-scripts-and-agents] `exec` never asks a question. The remote command's output streams through, and its exit status becomes `exec`'s, so `layerbeat exec agent-01 -- test -f /etc/app.conf` works in an `if`. With `--json` the output is captured instead: ```bash layerbeat exec agent-01 --json -- systemctl is-active caddy # {"exit_code": 0, "stdout": "active\n", "stderr": ""} ``` Then the CLI exits 0 once the command ran (whatever its own exit code), and 9 if SSH itself failed. `--timeout` sets how many seconds to wait for the connection (default 10). ## Log-in user and keys [#log-in-user-and-keys] The CLI logs in as the server's own login user (`root` or `ubuntu`, depending on the image) with the SSH keys you chose when buying. Servers bought with a password: read it with `layerbeat password reveal agent-01`. Windows servers use Remote Desktop rather than SSH; see [Windows servers](/guides/windows). # Templates (https://docs.layerbeat.com/cli/templates) Templates are software made and reviewed by Layerbeat — coding agents (Claude Code, Codex, Cursor CLI, OpenCode, Pi, omp, herdr, luvus), Docker, Caddy, HTTPS for your app, Supabase — that Layerbeat installs on your running Linux server for you. No SSH, and your settings reach the server as data, never as commands. ## Find one [#find-one] ```bash layerbeat template ls # the catalog, no sign-in needed layerbeat template show supabase # what it installs, its settings, ports and README ``` ## Deploy [#deploy] ```bash layerbeat template deploy claude-code --server agent-01 --wait layerbeat template deploy https-proxy --server agent-01 \ --input domain=app.example.com --input upstream=127.0.0.1:3000 \ --accept-ports --wait ``` - `--input NAME=VALUE` fills a setting (repeatable); `template show` lists them. - A template that opens ports to the internet needs your agreement: `--ports 80,443`, or `--accept-ports` for exactly the ports it lists (they are printed before anything happens). Layerbeat opens only ports that aren't open yet, and closes them again when you remove the template. - Templates it needs are deployed first: HTTPS for an app brings Caddy; Supabase brings Docker and Caddy. ## Follow and manage [#follow-and-manage] ```bash layerbeat template deployments # what is deployed where layerbeat template status claude-code --server agent-01 layerbeat template check claude-code --server agent-01 # run its health check now layerbeat template update dep_... # the latest version, or retry a failed run layerbeat template rm supabase --server agent-01 # data is kept… layerbeat template rm supabase --server agent-01 --delete-data # …unless you ask ``` A deployment can be named by its `dep_...` ID, or by the template with `--server`. | Status | Meaning | | --- | --- | | `deploying` | Being installed | | `ready` | Done. A **service** (Caddy, Docker, HTTPS for an app, Supabase) is running; a **tool** (the coding agents) is installed, ready for you to run | | `failed` | The script reported a problem; see the output with `template status`, then retry with `template update` | | `unknown` | The result couldn't be confirmed. Run `template check`, then `template update` to retry. Layerbeat never re-runs a script on its own | | `removing`, `removed` | Being removed, or gone | ## See exactly what runs [#see-exactly-what-runs] ```bash layerbeat template script https-proxy --input domain=app.example.com layerbeat template script dep_... ``` This prints the full script the server receives: Layerbeat's short header, which passes your settings as data and reports the result, then the template's reviewed install script. Editing a template's script before deploying (`template deploy --script FILE`) is not available yet; Layerbeat runs the reviewed scripts only. # Set up your account (https://docs.layerbeat.com/guides/account) Create your account at [the Layerbeat console](https://layerbeat.com/console/?auth=signup). You can use email and password, or an available Google or GitHub sign-in option. ### Register and verify your email [#register-and-verify-your-email] For email signup, use a password of 10–72 bytes and confirm the address using the verification email. A verified email is required for production top-ups and for joining another workspace. If the message does not arrive, check spam and request another verification email from your account. A verification link expires after 30 minutes and can be used once. ### Complete onboarding [#complete-onboarding] Choose your default billing currency, enter a workspace name and optionally add a referral code. Your currency preference controls the balance and prices shown in the console; it does not move or convert money. ### Prepare for your first purchase [#prepare-for-your-first-purchase] Add [personal credit](/guides/money) and choose an [SSH key or password](/guides/secure-access). Then [create a VPS](/guides/servers). ## Change account settings [#change-account-settings] Open **Account settings** in the console to change your default billing currency, manage linked sign-in methods and review email preferences. Existing payments, quotes and purchases keep their recorded currency and amount. Use `GET /v1/me` to inspect your identity and workspace access. Account preferences are available through `GET /v1/me/preferences` and `PATCH /v1/me/preferences`; changing them requires a signed-in session. ## Recover your account [#recover-your-account] Use **Forgot password** on the sign-in page. Recovery links expire after 30 minutes and work once. Completing a reset signs out existing sessions, revokes your API keys across workspaces and disconnects linked Google/GitHub sign-ins. Sign in with your new password, then recreate keys and reconnect the methods you need. The first email verification also removes access created before the address was verified. Create your long-lived API keys after verification. If you have several workspaces, choose one in the console header. Switching workspaces changes the servers you manage, while your credit remains personal. # Agent payments (https://docs.layerbeat.com/guides/agent-payments) An agent can add personal credit to its Layerbeat account without a person paying for it: it asks for a top-up, receives `402 Payment Required`, pays from its own wallet and repeats the request. Layerbeat supports two protocols: | Protocol | Network and token | Clients | Endpoint | | --- | --- | --- | --- | | x402 V2 (`exact`) | Solana, native USDC | [pay](https://pay.sh) (`pay curl`), x402 SDKs | `POST /v1/billing/top-ups/x402` | | MPP (`tempo` charge) | Tempo, USDC.e | [mppx](https://mpp.dev), pympp and other MPP clients | `POST /v1/billing/top-ups/mpp` | Both add **USD credit** to the user who owns the API key. Neither buys anything by itself: the agent then orders a VPS with the API, the [CLI](/cli) or its MCP tools, spending that credit. Both endpoints need a Layerbeat API key with `billing:write`. The payment travels in its own header (`PAYMENT-SIGNATURE` or `Payment-Authorization`), so the key and the payment never replace each other. Give agents their own key and keep keys and wallet secrets out of prompts and logs. ## From start to finish [#from-start-to-finish] An agent with an API key (`billing:read`, `billing:write`, `vm:read`, `vm:write`) and a wallet can go from no credit to a running server: ```bash layerbeat credit --currency USD # 1. what is there layerbeat topup 10 --pay x402 --yes # 2. add $10 from the agent's Solana wallet layerbeat quote --region sgp --plan SG-B224 --image "Ubuntu 24.04" # 3. price the server layerbeat new web-1 --region sgp --plan SG-B224 --image "Ubuntu 24.04" \ --ssh-key agent --max-price 10 --idempotency-key web-1-001 --yes --wait # 4. buy it, never above $10 ``` Use `--pay mpp` to pay with USDC.e on Tempo instead. Through MCP, the same steps are the `credit`, `top_up` (with `pay`), `quote` and `create_server` tools, available when the server runs with `layerbeat mcp serve --allow-spend`. ## With the Layerbeat CLI [#with-the-layerbeat-cli] `layerbeat topup --pay x402` runs [pay](https://pay.sh) and `--pay mpp` runs [mppx](https://mpp.dev) to pay from this computer's wallet. See [Credit](/cli/credit#let-an-agent-pay). - **The key stays in the CLI.** The payer never receives your Layerbeat key: the CLI gives it a one-time address on `127.0.0.1` and forwards only this top-up. - **The amount is capped.** The CLI refuses an offer above the amount, plus the identifying suffix of under one cent. - **It never pays twice.** Retrying with the same `--idempotency-key` cannot pay again. ## With pay.sh [#with-paysh] [pay](https://pay.sh) wraps `curl` and pays HTTP 402 challenges from a local wallet. It sends the same request again with your headers, so the API key and idempotency key stay in place: ```sh pay curl -X POST https://layerbeat.com/v1/billing/top-ups/x402 \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H "Idempotency-Key: agent-topup-001" \ -H "Content-Type: application/json" \ --data '{"amount":"5.00"}' ``` The offered amount is a few micro-USDC above the round figure (for example `5.004213`). That suffix identifies your payment and is kept as credit. ## From code [#from-code] Each example pays a $5.00 top-up and reads the API key, a top-up key and the wallet from the environment. `TOPUP_KEY` identifies one top-up: reuse it for every retry. ```js // npm install @x402/fetch @x402/svm @solana/kit @scure/base import { x402Client, wrapFetchWithPayment } from '@x402/fetch' import { ExactSvmScheme } from '@x402/svm/exact/client' import { createKeyPairSignerFromBytes } from '@solana/kit' import { base58 } from '@scure/base' const signer = await createKeyPairSignerFromBytes(base58.decode(process.env.SVM_PRIVATE_KEY)) const client = new x402Client() client.setSpendControls({ maxAmountPerPayment: '$5.01' }) // the amount plus the suffix client.register('solana:*', new ExactSvmScheme(signer)) const fetchWithPayment = wrapFetchWithPayment(fetch, client) const res = await fetchWithPayment('https://layerbeat.com/v1/billing/top-ups/x402', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.LAYERBEAT_API_KEY}`, 'Idempotency-Key': process.env.TOPUP_KEY, }, body: JSON.stringify({ amount: '5.00' }), }) console.log(res.status, (await res.json()).status) // 201 paid ``` ```python # pip install "x402[httpx,svm]" "solana<0.40" import asyncio, os from x402 import x402Client from x402.http.clients import x402HttpxClient from x402.mechanisms.svm import KeypairSigner from x402.mechanisms.svm.exact.register import register_exact_svm_client async def main(): client = x402Client().set_spend_controls({"max_amount_per_payment": "$5.01"}) register_exact_svm_client(client, KeypairSigner.from_base58(os.environ["SVM_PRIVATE_KEY"])) async with x402HttpxClient(client) as http: r = await http.post( "https://layerbeat.com/v1/billing/top-ups/x402", json={"amount": "5.00"}, headers={ "Authorization": f"Bearer {os.environ['LAYERBEAT_API_KEY']}", "Idempotency-Key": os.environ["TOPUP_KEY"], }, ) await r.aread() print(r.status_code, r.json()["status"]) # 201 paid asyncio.run(main()) ``` `solana<0.40` is needed until the x402 SDK supports the latest solana-py. ```js // npm install mppx viem import { Mppx, tempo } from 'mppx/client' import { privateKeyToAccount } from 'viem/accounts' const account = privateKeyToAccount(process.env.TEMPO_PRIVATE_KEY) const mppx = Mppx.create({ methods: [tempo.charge({ account })], polyfill: false }) const res = await mppx.fetch('https://layerbeat.com/v1/billing/top-ups/mpp', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.LAYERBEAT_API_KEY}`, // the payment goes in Payment-Authorization 'Idempotency-Key': process.env.TOPUP_KEY, }, body: JSON.stringify({ amount: '5.00' }), }) console.log(res.status, (await res.json()).status) // 201 paid ``` ```python # pip install "pympp[tempo]" import asyncio, os from mpp.client import Client from mpp.methods.tempo import ChargeIntent, TempoAccount, tempo async def main(): account = TempoAccount.from_key(os.environ["TEMPO_PRIVATE_KEY"]) method = tempo(account=account, intents={"charge": ChargeIntent()}) async with Client(methods=[method]) as client: r = await client.post( "https://layerbeat.com/v1/billing/top-ups/mpp", json={"amount": "5.00"}, headers={ "Authorization": f"Bearer {os.environ['LAYERBEAT_API_KEY']}", "Idempotency-Key": os.environ["TOPUP_KEY"], }, ) print(r.status_code, r.json()["status"]) # 201 paid asyncio.run(main()) ``` A `202` means the payment is still confirming: run the same code again with the same `TOPUP_KEY`. ## How MPP payments are checked [#how-mpp-payments-are-checked] The MPP challenge (`WWW-Authenticate: Payment`, `method="tempo"`, `intent="charge"`) offers two ways to pay, and both carry mppx's attribution memo for this challenge: - **Push:** your wallet broadcasts a `transferWithMemo` of the exact amount to the recipient, and the credential carries the transaction hash. - **Pull:** the credential carries the signed transaction and Layerbeat broadcasts it, once. Layerbeat broadcasts only a transaction that makes exactly that one call on this chain, pays its own fee and, if it expires, expires no later than the challenge. | Response | Meaning | What to do | | --- | --- | --- | | `402` with a challenge | Payment required | Pay the exact `amount` of `currency` to `recipient` | | `201` with `Payment-Receipt` | A final transfer credited your wallet | Done | | `202` | The transaction is recorded but not final | Repeat the request; do not pay again | | `503` `payment_not_final` | Your broadcast transaction is not final yet | Send the same credential again in a few seconds | | `402` with `error: payment_verification_failed` | The transaction does not pay this challenge (amount, token, recipient, memo, or it failed) | Check it. A transfer of the exact amount is still credited by the payment watcher | ## Never pay twice [#never-pay-twice] - Reuse the same `Idempotency-Key` for every retry of one top-up. A new key means a new payment. - A wallet's or facilitator's "success" is not credit. Only a finalized on-chain transfer, verified by Layerbeat, adds credit, and each transfer counts once. - If a request fails after you paid, replay it or check the payment. If the agent stopped right after paying, the payment watcher still credits a transfer of the exact amount. The limits of ordinary top-ups apply: $5 minimum and $1,000 maximum per top-up, at most 5 unpaid top-ups at a time and 20 started in 24 hours, and the account must be eligible for funding. Transfers under one cent are ignored. See [Credit and billing](/guides/money) and [Building with agents](/guides/agents). # Build for AI agents (https://docs.layerbeat.com/guides/agents) Start an agent with [`layerbeat.com/llms.txt`](https://layerbeat.com/llms.txt), a short brief on what Layerbeat sells and how to buy it, and [`layerbeat.com/pricing.md`](https://layerbeat.com/pricing.md), the live price list with plan IDs. See [Pricing](/guides/pricing). To let Claude Code, Codex, Cursor or opencode manage Layerbeat as tools, see [Agents and MCP](/cli/agents). An agent can also use the same API and [CLI](/cli) as a person. Give it a dedicated API key, explicit spending limits and durable request identities. A key's purchases and top-ups act on its creator's personal credit. ## Give the agent a narrow role [#give-the-agent-a-narrow-role] Create a key in the workspace where the agent should operate. Use `vm:read` and `vm:write` for server management; add `ssh_key:write` if it will register keys. Add billing scopes only when it needs to inspect or fund personal credit. If it needs metrics, grant its key access to specific servers through the [metrics access list](/guides/metrics). ## Make purchases predictable [#make-purchases-predictable] ### Read and quote [#read-and-quote] Fetch available catalog IDs, request a quote in one currency and compare the full term total with the user's spending policy. Do not assume a plan name or old price is still valid. ### Fund credit when authorized [#fund-credit-when-authorized] If the selected balance is insufficient, request a top-up through the approved payment method. Wait for confirmed credit before submitting a purchase. The wallet authorization belongs in your agent's secure payment integration, not in Layerbeat's API key. ### Submit and follow the original operation [#submit-and-follow-the-original-operation] Persist the request body and idempotency key before sending. Save the server and operation IDs, then poll the operation. Recover lost responses with the original request identity. With the CLI, `new --max-price` supplies a spending guard, `--idempotency-key` supplies the retry identity and `--wait` follows the operation. Use `--json` and `--no-input` for automation. ## Top up using x402 [#top-up-using-x402] For pay.sh and MPP on Tempo, see [Agent payments](/guides/agent-payments). Layerbeat supports x402 V2 exact USDC top-ups on the configured Solana network. This endpoint funds USD credit; it does not directly pay for a particular VPS. | Step | Request or result | | --- | --- | | Request requirements | `POST /v1/billing/top-ups/x402` with `{"amount":"5.00"}` and a saved `Idempotency-Key` | | Inspect requirements | `402` with the payment requirements in the body and `PAYMENT-REQUIRED` header | | Authorize | Prepare the exact offered USDC transaction using the specified network, mint, recipient, fee payer and memo | | Submit | Repeat the same body and key with the base64-encoded x402 payload in `PAYMENT-SIGNATURE` | | Confirm | `201` means finalized credit; `202` means pending credit—poll the saved payment | The initial x402 request still needs a Layerbeat bearer token with `billing:write`. Save `extensions.layerbeat.info.payment_id` from the requirements. The offered amount is an integer in micro-USDC, including the original payment's attribution suffix. The current transaction profile supports regular-wallet native USDC checked transfers. Smart-wallet transactions and address lookup tables are not supported. Use the offered requirements instead of constructing a different transfer or removing its memo. ## Recover without paying twice [#recover-without-paying-twice] After an uncertain submission, poll `GET /v1/billing/payments/{id}` or replay the original x402 request with the same key. Do not authorize a replacement transfer just because an HTTP response was lost. Wallet or facilitator success alone is not spendable credit. Only the confirmed backend receipt updates the wallet. Keep payment authorizations, API keys and signed payloads out of agent transcripts and logs. The docs also provide [llms.txt](/llms.txt), [full Markdown](/llms-full.txt) and a copy-Markdown control on each page for your integration's context. # Track asynchronous operations (https://docs.layerbeat.com/guides/asynchronous-operations) Creating, renewing, deleting or changing a server's power state can take time. These requests return `202 Accepted` with an operation. Keep its ID and poll it: ```bash curl -sS "$BASE/v1/operations/$OPERATION_ID" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` | Operation status | Meaning | | --- | --- | | `pending` | Accepted and waiting for a worker | | `running` | Work is in progress | | `succeeded` | The requested result is confirmed | | `failed` | Processing stopped; inspect `error` and any retained hold | The response also includes `steps`, `vm_id`, `result`, `error`, `created_at` and `finished_at`. Use `steps` for progress displays, but use the overall status to decide whether the task completed. ## Poll without submitting another order [#poll-without-submitting-another-order] Poll every few seconds and slow down with backoff while waiting. Stop on a terminal status and respect [rate limits](/guides/rate-limits). After a successful purchase, fetch the server to read its public IP. After renewal, fetch it to confirm the recorded expiry. Do not treat an HTTP `202` as a running server or a completed charge. A failed operation can retain a reservation when the external result is not yet known. Read the error and wallet before deciding what to do. A fresh purchase or renewal is not a safe way to recover an uncertain one. If the initiating HTTP request times out before you receive an operation ID, retry its original body with the [same idempotency key](/guides/idempotency). This retrieves the accepted result instead of creating another purchase. # Audit history (https://docs.layerbeat.com/guides/audit-trail) The workspace audit log records security and management events such as key changes, member changes, purchases, deletion requests, firewall changes and console access. Records are append-only. Read it with an owner/admin **session**: ```bash curl -sS "$BASE/v1/audit-log?limit=25" \ -H "Authorization: Bearer $SESSION" \ -H "X-Org-ID: $WORKSPACE_ID" ``` API keys cannot read the audit log. Use [cursor pagination](/guides/pagination) to retrieve older events. ## Investigate a change [#investigate-a-change] Start with the affected resource ID and time. Review its related audit records, then fetch the resource or operation to see the current state. An audit event records an action; it does not replace the operation's completion status. After a team member leaves, confirm they are removed and review the keys they created. Existing keys become invalid when their creator is removed from that workspace. Role changes also reduce or restore their effective key permissions. ## Review personal billing [#review-personal-billing] Use `GET /v1/billing/transactions` for your credit ledger and `GET /v1/billing/payments` for your payment history. These remain private to the authenticated user, including in a shared workspace. For support investigations, save request, operation and resource IDs. Keep credentials and console URLs out of exported logs. # Authentication and API keys (https://docs.layerbeat.com/guides/authentication) Send a bearer token on authenticated API requests: ```bash curl -sS https://layerbeat.com/v1/me \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` The API examples throughout these guides use `BASE=https://layerbeat.com` and a key stored in `LAYERBEAT_API_KEY`. Set the base URL once and load the key from your secure environment: ```bash export BASE=https://layerbeat.com ``` Public catalog endpoints do not require a token. Browser sessions and API keys serve different purposes: | Credential | Purpose | Lifetime | | --- | --- | --- | | Session (`lb_sess_…`) | Signing in and managing your account, keys and workspace membership | Seven days, or until revoked | | API key (`lb_live_…`) | Applications, scripts and agents in one workspace | Until revoked or its optional expiry | The console uses protected cookies for browser sessions. Use an API key for your own automation; do not copy browser cookies into a script. ## Create a key [#create-a-key] Open **Access & keys** in the console. Give the key a recognizable name, choose its scopes and set an expiry if needed. Copy the secret when it is shown: you cannot retrieve it later. Creating or revoking API keys requires an owner/admin session. An API key cannot create another key, manage sessions or change workspace membership. | Scope | Allows | | --- | --- | | `vm:read` | Read servers, quotes, firewall rules and operations | | `vm:write` | Purchase, renew, delete and manage servers; open console access; edit firewall rules | | `ssh_key:read` | List workspace SSH keys | | `ssh_key:write` | Register and remove SSH keys | | `billing:read` | Read the creator's credit, transactions and payments | | `billing:write` | Create top-ups for the creator's personal credit | Metrics require `vm:read` **and** an explicit server grant for API keys. See [metrics access](/guides/metrics). ## How permissions change [#how-permissions-change] A key is limited by its creator's current workspace role. A role downgrade reduces access immediately; removing the member invalidates their keys in that workspace. A key's billing actions always use its creator's personal account. Password recovery revokes all your API keys. First email verification also revokes keys created before verification. Verify your email before setting up production automation. ## Store and rotate keys [#store-and-rotate-keys] Keep keys in your application's secret manager or environment. Avoid putting them in source code, command-line arguments, screenshots or logs. Use a separate key for each integration so you can revoke one without interrupting the others. To rotate a key, create a replacement, update the integration, confirm it can call `GET /v1/me`, then revoke the old key. A revoked key returns `401` on subsequent requests. For workspace selection and member permissions, see [organizations and roles](/guides/organizations-and-roles). # Locations, images and plans (https://docs.layerbeat.com/guides/catalog) The public catalog lists locations, available configurations and supported operating systems or applications. Read it before preparing an order; availability and prices can change. ```bash curl -sS https://layerbeat.com/v1/regions curl -sS 'https://layerbeat.com/v1/plans?region=sgp' curl -sS 'https://layerbeat.com/v1/images?region=sgp' ``` Use each response's `id` when making API requests. Display names help you compare configurations, but are not a replacement for IDs. ## Choose a location [#choose-a-location] Choose a region near the people or services using your machine. The region's `available` flag indicates whether it currently accepts new purchases. The `sgp` ID used here is Singapore; read `/v1/regions` for the current list. ## Compare plans [#compare-plans] | Field | Meaning | | --- | --- | | `vcpu` | Virtual CPU count | | `memory_mb` | RAM in MiB | | `disk_gb` | System disk capacity | | `bandwidth_mbps` | Network speed | | `traffic_gb` | Included monthly transfer | | `traffic_unlimited` | Whether transfer is unmetered | | `family` | General VPS or Fast VPS category | | `regions[].in_stock` | Current stock in that location | | `regions[].prices` | Available terms and prices for that location | A compact name such as `SG-B224` identifies its country and hardware configuration. Use the listed CPU, RAM, disk, speed and transfer values when comparing plans with similar names. Only choose a term present in the plan's regional prices. A listed plan can be temporarily out of stock; a purchase may still return `409 out_of_stock` if stock changes after you read the catalog. ## Choose an image [#choose-an-image] `type: os` is a base operating system. `type: app` includes preinstalled software. Check the image's version, availability and minimum RAM/disk requirements against your selected plan. A disabled or incompatible image cannot be purchased. ## Lock a quote [#lock-a-quote] `POST /v1/quotes` checks the combination and returns the full prepaid total in USD or IDR. Send the selected `region`, `plan`, `image`, `term_months` and `currency`. The returned quote is valid for 10 minutes. Pass its `id` as `quote_id` in the purchase request and keep the same configuration and currency. Changing a selection requires a new quote. A quote locks a price; it does not reserve supplier stock or reserve your credit. For purchase examples, continue to [create a VPS](/guides/servers). # Disks (https://docs.layerbeat.com/guides/disks) A disk is extra block storage for a server. It keeps its data when it is detached or when its server ends, and can be attached to another server in the same zone. ## Choose type and size [#choose-type-and-size] ```bash curl -sS 'https://layerbeat.com/v1/disk-prices' curl -sS 'https://layerbeat.com/v1/volume-options?region=sgp&type=premium' \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` | Type | Use | | --- | --- | | `premium` | General storage; the default | | `ssd` | Faster storage for databases and busy workloads | `min_gb` is the smallest size sold, `max_gb` the largest and `step_gb` the size increment. `in_stock: false` means the region is sold out; a purchase then returns `409 out_of_stock`. The price is size × price per GB-month × months, for 1, 3 or 12 months. ## Buy a disk for a server [#buy-a-disk-for-a-server] Give `vm_id` and the disk is created in the server's zone, attached and mounted once the server runs. ```bash curl -fsS https://layerbeat.com/v1/volumes \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"name":"data","vm_id":"vm_...","type":"premium","size_gb":50,"term_months":1,"currency":"USD"}' ``` To buy a disk without a server, give `region` and `zone` instead of `vm_id`. Keep the `Idempotency-Key` and request body if you need to retry; see [safe retries](/guides/idempotency). ## Where it is mounted [#where-it-is-mounted] | Server | Mount path | | --- | --- | | Linux | `/mnt/`, formatted `ext4` the first time | | Windows | `C:\mnt\`, formatted NTFS the first time | A new disk is formatted only the first time it is mounted. A disk that already holds data is mounted as it is. If it cannot be mounted automatically it stays attached and unmounted, with a `note`, and its data is not changed. ## Attach, detach and renew [#attach-detach-and-renew] - `POST /v1/volumes/{id}/attach` with `vm_id`: the server must be running and in the same zone. - `POST /v1/volumes/{id}/detach`: unmounts first. A disk in use fails with `volume_busy` and stays attached. - `POST /v1/volumes/{id}/renew` with `term_months`: extends the term. An expired disk can be renewed only for a short time before its data is erased. - `PATCH /v1/volumes/{id}` with `name`: renames the disk. - `DELETE /v1/volumes/{id}`: deletes the disk and its data. The remaining term is not refunded. # Errors and troubleshooting (https://docs.layerbeat.com/guides/errors) API errors contain a stable code, a readable message and a request ID: ```json { "error": { "code": "insufficient_balance", "message": "Wallet balance is lower than the order total.", "request_id": "req_EXAMPLE", "details": { "required": "12.00", "available": "0.00", "currency": "USD" } } } ``` Branch on `error.code`, not the message text. `details` may be absent or null. ## Common responses [#common-responses] | HTTP/code | Recommended action | | --- | --- | | `400 invalid_request` | Correct the fields or amount format; consult the request schema | | `401 unauthorized` / `invalid_credentials` | Check the credential, expiry and revocation status | | `403 forbidden` | Check the key's scopes and creator's current workspace role | | `404 not_found` | Check the ID, selected workspace and any server-specific metric grant | | `402 insufficient_balance` | Fund the selected personal balance and wait for confirmed credit | | `409 idempotency_conflict` | Recover the original body; do not reuse its identity for another action | | `409 quote_expired` | Obtain and review a new quote before a new purchase attempt | | `409 out_of_stock` / `quota_exceeded` | Choose an available configuration or wait for availability | | `409 invalid_state` / `conflict` | Read the current server, operation or payment before changing it | | `429 rate_limited` | Wait for `Retry-After` and retry with backoff | | `503 funding_unavailable` | Check the existing payment; do not assume an unknown checkout failed | | `503 purchases_paused` / `renewals_paused` | New orders are paused; follow existing accepted operations | | `503 provider_unavailable` / `500 internal` | Record the request ID; recover financial requests using their original key | ## A payment has not credited [#a-payment-has-not-credited] Read the original payment. For a stablecoin transfer, check its network, token, transaction and reference against the stored instructions. For local checkout, request a refresh of the same payment. A wallet approval or browser return alone is not confirmation. Do not authorize another transfer to resolve a missing credit. Contact support with the payment ID and transaction signature or gateway reference. ## A server operation failed or is taking time [#a-server-operation-failed-or-is-taking-time] Read `/v1/operations/{id}` and the server's state. Check the selected wallet's `held` and `available` amounts. Uncertain external results can retain a hold while the original order is reconciled. A timeout is not proof that a purchase or renewal failed. Retry the original request identity to recover its result; avoid submitting another order with a new key. ## A browser request reports an origin error [#a-browser-request-reports-an-origin-error] Use the console from its configured Layerbeat origin. Browser cookie actions use origin and CSRF checks; cross-origin scripts cannot reuse those cookies. Server integrations should use the public API with a bearer API key. ## Contact support [#contact-support] Include the request ID, relevant server/payment/operation ID, approximate time and the action you attempted. Share redacted responses. Do not send API secrets, session tokens, initial passwords, console URLs or wallet seed phrases. # Safe retries with idempotency (https://docs.layerbeat.com/guides/idempotency) An idempotency key identifies **one intended action**. Generate it before the first request, save it with the body and reuse both for every retry of that action. ```bash export REQUEST_ID=$(uuidgen) curl -sS -X POST "$BASE/v1/vms" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $REQUEST_ID" \ --data-binary @purchase.json ``` If the connection drops, repeat the saved request with the same key. Reusing a key with a different request returns `409 idempotency_conflict`. ## Where to use it [#where-to-use-it] | Action | Endpoint | | --- | --- | | VPS purchase | `POST /v1/vms` | | Manual renewal | `POST /v1/vms/{id}/renew` | | Credit top-up | `POST /v1/billing/top-ups` | | Agent top-up | `POST /v1/billing/top-ups/x402` | Always use keys for financial requests. Native Doit checkout and x402 require them. Use a unique non-secret string of up to 128 characters, such as a UUID or a durable job ID. Purchase identities are workspace-scoped. Top-up identities are personal and continue to identify the same top-up if that user switches workspaces. An accepted purchase retains its recorded payer, currency, amount and operation. ## When to create a new key [#when-to-create-a-new-key] Use a new key for an intentionally separate purchase or top-up. Use the original key when the outcome of the first attempt is uncertain. Persist it across process restarts; generating a UUID inside an automatic retry loop creates a new action each time. A quote may expire or a configuration may become unavailable before acceptance. Review that error and check whether any operation was accepted before changing the request. A browser reload alone is not a reason to submit another order. For payments, idempotency protects the Layerbeat request. It cannot prevent you from manually authorizing a second blockchain transfer. Keep the original transaction and payment details when wallet submission is uncertain. # Metrics and transfer (https://docs.layerbeat.com/guides/metrics) Open a server's **Metrics** tab to see its last 24 hours of CPU, memory, disk and public network activity. Monthly transfer is a separate reading; it is not the same as current network speed. ## Read metrics through the API [#read-metrics-through-the-api] ```bash curl -sS "$BASE/v1/vms/$VPS_ID/metrics" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Samples cover a rolling 24-hour window at 300-second intervals. A snapshot is cached for five minutes. Repeated requests reuse that snapshot while it is fresh, but authorization is checked on every request. Each series reports `unit`, `available`, `stale`, `latest_at` and timestamped `points`. Missing samples are omitted, not replaced with zero. If no data is available, `available` is false and `points` is empty. A stale value may not represent the server's current activity. The collection window ends slightly in the past to allow metrics to arrive. These values are aggregated samples, rather than instantaneous measurements. ## Grant access [#grant-access] Owner/admin **sessions** can read metrics automatically. Other member sessions need an explicit server grant. **Every API key**, including an owner's key, needs `vm:read` and an explicit grant. An owner/admin can edit the access list on the server page or use `PUT /v1/vms/{id}/metrics/access` with a session: ```json { "user_ids": ["usr_YOUR_MEMBER_ID"], "api_key_ids": ["key_YOUR_API_KEY_ID"] } ``` Use actual IDs from your workspace. Both arrays are required, and the request replaces the **entire** explicit list. Empty arrays revoke all explicit grants; automatic owner/admin session access remains. API keys cannot change these grants. The total limit is 100 grants. Foreign, removed or inactive recipients are rejected without changing the existing list. An ungranted caller receives `404` even when metric data is cached. ## Read monthly transfer [#read-monthly-transfer] ```bash curl -sS "$BASE/v1/vms/$VPS_ID/traffic" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Compare the reported usage with the plan's included transfer. For connection issues, also inspect [firewall rules](/guides/networking). # Credit and billing (https://docs.layerbeat.com/guides/money) Layerbeat uses personal prepaid credit. Add credit first, then purchase products for a workspace. A payment does not automatically create or renew a VPS. ## Two separate balances [#two-separate-balances] | Balance | How to fund it | API amount format | | --- | --- | --- | | USD | USDC on an enabled network | Decimal string, such as `"25.00"` | | IDR | An enabled Rupiah gateway | Whole-Rupiah string, such as `"100000"` | Your default billing currency controls the balance and product prices shown in the console. Change it in **Account settings**. Changing the preference does not convert credit, combine balances or change existing purchases. A purchase uses one selected balance. If USD credit is insufficient, IDR credit is not used to cover the difference, and vice versa. Workspace owners cannot spend or inspect another member's credit. API keys read, fund and spend their creator's credit, even when several people share the same workspace. ## Read your credit [#read-your-credit] ```bash curl -sS "$BASE/v1/billing/wallet" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` | Field | Meaning | | --- | --- | | `balance` | Recorded credit in this balance | | `held` | Credit reserved for accepted purchases or renewals | | `available` | Credit you can spend: balance minus held | | `currency` | The balance's currency | The `balances` object contains the separate native USD and IDR values. Monetary values are strings. Use integers or a decimal-money library in your application, rather than binary floating point. ## Add credit [#add-credit] Use the **+** beside your console balance, or call `GET /v1/billing/payment-methods` to list the currently enabled methods. Production top-ups require a verified, eligible account. Pay from a wallet to add USD credit. Use QRIS or an available virtual account to add IDR credit. Let an agent pay a top-up itself, with x402 on Solana or MPP on Tempo. The console offers IDR presets of Rp50.000, Rp100.000, Rp250.000 and Rp500.000. Follow the permitted amount range shown at checkout. You can have at most 5 unpaid USDC top-ups at a time and start 20 in 24 hours. Each one holds a unique amount until it is paid or expires. ## Check payment and transaction history [#check-payment-and-transaction-history] `GET /v1/billing/payments` lists your payment intents. `GET /v1/billing/transactions` lists your credit ledger, including top-ups, reservations, charges and releases. These are different records: a payment can be awaiting confirmation while no credit is available yet. A successful browser redirect, a wallet signature or a gateway webhook alone is not confirmation. Check the saved payment and your wallet before placing a product order. If a payment shows `review`, contact support with its payment ID. Verified reversals or inconsistencies can pause new purchases while reviewed. Do not create a replacement payment to work around that state. # Networking and firewall (https://docs.layerbeat.com/guides/networking) Read the server's `ipv4` after provisioning completes. Use public addresses for connections between your workspace's servers. The cloud firewall controls inbound access; your operating system and application must also accept the connection. ## View rules [#view-rules] ```bash curl -sS "$BASE/v1/vms/$VPS_ID/firewall-rules" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Reading rules requires `vm:read`. Adding and removing rules requires `vm:write`. ## Open HTTPS [#open-https] ```bash curl -sS -X POST "$BASE/v1/vms/$VPS_ID/firewall-rules" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"protocol":"tcp","port":"443","cidr":"0.0.0.0/0","action":"accept","description":"HTTPS"}' ``` Use an office or VPN CIDR for services that should be private. `0.0.0.0/0` allows the public internet. | Field | Accepted values | | --- | --- | | `protocol` | `tcp`, `udp`, `icmp` or `all` | | `port` | One port, a range such as `8000-8100`, or `ALL`; ignored for `icmp` and `all` | | `cidr` | Source network; defaults to `0.0.0.0/0` | | `action` | `accept` or `drop`; defaults to `accept` | | `description` | A short label, up to 64 characters | An identical rule returns `409 conflict`. A server supports at most 100 rules. ## Remove a rule [#remove-a-rule] Use the returned rule ID: ```bash curl -sS -X DELETE "$BASE/v1/vms/$VPS_ID/firewall-rules/$RULE_ID" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Check your current SSH access before removing its rule. If a port remains unreachable, verify that your application is listening on the public interface and that the guest firewall permits it. # Workspaces and roles (https://docs.layerbeat.com/guides/organizations-and-roles) The console calls an organization a **workspace**. Each account has at least one workspace. VPSs and SSH keys belong to a workspace; credit and payment history belong to individual users. ## Choose a workspace [#choose-a-workspace] Use the selector in the console header. With a session token, send `X-Org-ID` to select a workspace you belong to: ```bash curl -sS https://layerbeat.com/v1/vms \ -H "Authorization: Bearer $SESSION" \ -H "X-Org-ID: $WORKSPACE_ID" ``` API keys are already bound to the workspace where they were created. To automate another workspace, create a key there. ## Assign roles [#assign-roles] | Role | Workspace permissions | | --- | --- | | Viewer | Read servers and SSH keys | | Developer | Viewer access plus purchasing and managing servers and SSH keys | | Admin | Developer access plus API keys, audit history and management of developers/viewers | | Owner | Full workspace access, including management of admins and owners | Every role can read and top up **its own** personal credit. No role can spend or inspect another member's balance. Metrics have an additional [access list](/guides/metrics). ## Add a member [#add-a-member] Ask the person to register and verify their email. Then open **Team**, enter that verified address and choose a role. An unverified account cannot be added. An admin can manage developers and viewers. Owners can manage all roles, but the workspace must always keep at least one owner. ## Who pays for a shared server? [#who-pays-for-a-shared-server] The person submitting the purchase pays from their selected personal balance. When an API key purchases, its creator pays. Any authorized member can manually renew a server using their own credit. Automatic renewal uses the original purchaser's saved consent and credit. Adding someone to a workspace, changing their role or removing them does not move money between accounts. USD and IDR balances also remain separate. Removing a member revokes their keys in that workspace. Changing their role also changes what existing keys may do. Review consequential changes in the [audit trail](/guides/audit-trail). # Pagination and filters (https://docs.layerbeat.com/guides/pagination) Paginated endpoints return a `data` array and `next_cursor`. Request another page only when `next_cursor` is non-null. ```bash curl -sS "$BASE/v1/vms?limit=25" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` The default `limit` is 50; the permitted range is 1–100. Treat the cursor as an opaque value: do not decode or construct it. ## Request the next page [#request-the-next-page] ```bash curl -sS --get "$BASE/v1/vms" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ --data-urlencode 'limit=25' \ --data-urlencode "cursor=$NEXT_CURSOR" ``` Keep the same token, workspace and filters while walking a list. URL-encode the cursor instead of concatenating it into a query string. ## Filter servers [#filter-servers] `GET /v1/vms` supports `status` and `region` filters. The default list contains current servers. Use `status=terminated` to retrieve deleted-server history. ```bash curl -sS "$BASE/v1/vms?status=running®ion=sgp&limit=25" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Catalog endpoints and some account endpoints are not paginated. Check the endpoint reference for supported parameters rather than sending `cursor` to every list. # Pricing (https://docs.layerbeat.com/guides/pricing) Every price is a prepaid total for a fixed term, paid from your personal credit. Nothing is billed afterwards: no metered traffic, no overage and no invoice at the end of the month. ## Read the live price list [#read-the-live-price-list] | Source | Use it for | | --- | --- | | [`layerbeat.com/pricing.md`](https://layerbeat.com/pricing.md) | Every region, plan ID, specification and 1/3/12-month price as Markdown. Add `?region=sgp` for one region and `?currency=IDR` for rupiah. | | [`layerbeat.com/llms.txt`](https://layerbeat.com/llms.txt) | A short brief for AI agents: products, rules, regions, payment methods and the purchase steps. | | `GET /v1/plans?region=` | The same prices as JSON, with `regular_amount` and `intro_ends_at` while a launch price runs. | | `GET /v1/disk-prices` | Disk prices per region and type, with the smallest size sold. | | `POST /v1/quotes` | The exact total for one configuration, term and currency, valid for 10 minutes. | All of these are generated from the catalog the console charges from, so they always agree. Plan names such as `SG-B224` help people compare configurations; send the plan `id` to the API. ## Servers [#servers] - **Terms:** 1, 3 or 12 months, paid in advance. Longer terms show their full prepaid total. - **General VPS** includes a monthly transfer allowance. Past it, bandwidth may be reduced or outbound traffic paused until the allowance resets. You are never charged for traffic. - **Fast VPS** has higher bandwidth and unlimited transfer. - **Windows Server** plans include the Windows licence in the price. See [Windows servers](/guides/windows). - **Launch prices:** while a launch discount runs, the catalog shows the regular price and the date it ends. After that date new purchases pay the regular price. A server bought at a launch price renews at that same price. - **Taxes** are included in the prices shown. ## Disks [#disks] A disk costs size × price per GB-month × months, rounded up once per order. Each region and disk type has a smallest size that can be sold; smaller disks are not offered. See [Disks](/guides/disks). ## Currency [#currency] Each person has separate USD and IDR balances. A quote and purchase use one currency; balances are never combined or converted. USD credit comes from USDC, and IDR credit from local payment methods. See [Credit and billing](/guides/money). ## Refunds [#refunds] A term is paid in advance and is not refunded if you delete a server or disk before it ends. See the [Terms](https://layerbeat.com/terms) for the cases where we credit or refund. # Deploy your first VPS (https://docs.layerbeat.com/guides/quickstart) You need a verified Layerbeat account, available credit in your purchase currency and an SSH public key or password login method. A VPS purchase uses prepaid credit; creating a payment alone does not deploy a machine. ### Finish account setup [#finish-account-setup] [Register and complete onboarding](/guides/account). Choose your workspace and default billing currency. ### Add credit [#add-credit] Use the **+** button beside your balance. Choose USDC for USD credit or a local payment method for IDR credit. Complete checkout and wait until the balance updates. ### Create your VPS [#create-your-vps] Open **VPS → Create VPS**. Enter a server name, choose an image, location, available plan, secure access method and term. Review the total and purchase. ### Connect when ready [#connect-when-ready] Wait for the server to show **Running**. Copy its public IP and connect with your selected login method. For a key-based Linux server: ```bash ssh -i ~/.ssh/id_ed25519 root@YOUR_SERVER_IP ``` Use `curl` and `jq` for these examples. Complete email verification in the console, then create an API key under **Access & keys** with `vm:read`, `vm:write` and `ssh_key:write`. Add `billing:read` and `billing:write` if this integration will read or fund credit. ```bash export BASE=https://layerbeat.com read -rs -p 'Layerbeat API key: ' LAYERBEAT_API_KEY; echo export LAYERBEAT_API_KEY curl -sS "$BASE/v1/me" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` ### 1. Choose from the current catalog [#1-choose-from-the-current-catalog] ```bash curl -sS "$BASE/v1/regions" | jq '.data[] | {id, name}' export REGION=sgp curl -sS "$BASE/v1/plans?region=$REGION" | jq '.data' curl -sS "$BASE/v1/images?region=$REGION" | jq '.data' ``` Copy an available plan ID and a compatible image ID from these responses: ```bash export PLAN_ID=YOUR_PLAN_ID export IMAGE_ID=YOUR_IMAGE_ID ``` ### 2. Register your SSH public key [#2-register-your-ssh-public-key] ```bash SSH_KEY_ID=$(jq -n \ --arg name laptop \ --arg key "$(cat ~/.ssh/id_ed25519.pub)" \ '{name: $name, public_key: $key}' | \ curl -fsS "$BASE/v1/ssh-keys" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' --data-binary @- | jq -r '.id') ``` ### 3. Quote the purchase [#3-quote-the-purchase] ```bash jq -n --arg region "$REGION" --arg plan "$PLAN_ID" --arg image "$IMAGE_ID" \ '{region: $region, plan: $plan, image: $image, term_months: 1, currency: "USD"}' | \ curl -fsS "$BASE/v1/quotes" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' --data-binary @- > quote.json jq '{id, expires_at, total, wallet, available}' quote.json ``` Check `available`, `total` and `wallet.shortfall`. If credit is insufficient, [top up](/guides/money), wait for confirmation and obtain a fresh quote. Quotes last 10 minutes. ### 4. Submit once and track the result [#4-submit-once-and-track-the-result] ```bash export CREATE_REQUEST_ID=$(uuidgen) jq -n --arg name agent-01 --arg region "$REGION" --arg plan "$PLAN_ID" \ --arg image "$IMAGE_ID" --arg key "$SSH_KEY_ID" --arg quote "$(jq -r '.id' quote.json)" \ '{name: $name, region: $region, plan: $plan, image: $image, term_months: 1, currency: "USD", quote_id: $quote, auth: "ssh_key", ssh_key_ids: [$key], auto_renew: false}' > purchase.json curl -fsS "$BASE/v1/vms" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $CREATE_REQUEST_ID" \ --data-binary @purchase.json > purchase-result.json export OPERATION_ID=$(jq -r '.operation.id' purchase-result.json) export VPS_ID=$(jq -r '.vm.id' purchase-result.json) curl -sS "$BASE/v1/operations/$OPERATION_ID" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" curl -sS "$BASE/v1/vms/$VPS_ID" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Poll the operation until `succeeded` or `failed`; `202` means accepted, not ready. On success, use the server's `ipv4` for SSH. On a request timeout, retry the saved body with the **same** `CREATE_REQUEST_ID`. ## Next steps [#next-steps] Add a firewall rule for your service. Review expiry and automatic renewal settings. # Rate limits (https://docs.layerbeat.com/guides/rate-limits) Layerbeat applies separate budgets to catalog reads, authenticated reads, writes and purchases. Requests are paced with a burst allowance, so a per-minute limit is not a promise that the entire minute's budget can be sent at once. | Class | Typical requests | Sustained requests/minute | | --- | --- | --- | | Public catalog | Regions, plans and images; per client IP | 120 | | Read | Authenticated GET requests | 600 | | Write | Most authenticated POST, PATCH and DELETE requests | 60 | | Purchase | `POST /v1/vms` | 10 | Signup, sign-in and recovery have additional anti-abuse limits. Signup is limited per address; sign-in and recovery also use the email address and client IP, with a separate account-wide ceiling. ## Read the headers [#read-the-headers] | Header | Meaning | | --- | --- | | `X-RateLimit-Limit` | Sustained requests per minute for the relevant class | | `X-RateLimit-Remaining` | Currently available request allowance | | `X-RateLimit-Reset` | Reset time as Unix seconds | | `Retry-After` | Minimum wait in seconds after a rejected request | The headers describe the budget for that request. Do not assume read and purchase budgets are interchangeable. ## Handle 429 [#handle-429] Wait at least the `Retry-After` duration, then retry with backoff and jitter. For a purchase or top-up, retain its original [idempotency key](/guides/idempotency). Use a modest polling interval for payments and operations. Repeatedly submitting an action is not a substitute for reading its status. # Refer & Earn (https://docs.layerbeat.com/guides/referrals) Open **Refer & Earn** in the console to activate referrals for your workspace. Activation requires an owner/admin session and creates a short, eight-character code. Repeating activation returns the same code. ## Invite someone [#invite-someone] Share the invite link or code shown on the page. A new customer can provide it during account setup. Activating a code or registering a new account does not immediately award credit. Rewards depend on the program's current eligibility rules and qualifying paid purchases. Self-referrals and shared payment-source abuse do not qualify. Read the displayed terms and reward status instead of treating a signup count as earned money. ## Track rewards [#track-rewards] The console separates referred customers, pending rewards, available earnings and payout history. The API offers: | Endpoint | Use | | --- | --- | | `GET /v1/affiliates` | Program status and your invite details | | `GET /v1/affiliates/referrals` | Referred-account activity | | `GET /v1/affiliates/rewards` | Reward eligibility and status | | `GET /v1/affiliates/statement` | Earnings history | | `GET /v1/affiliates/payouts` | Payout requests and their status | These actions use the program's authorized session access. They do not expose another customer's email, personal wallet or server credentials. ## Apply as a partner [#apply-as-a-partner] After activation, a verified owner/admin can submit a website or community URL and a description of how they will introduce Layerbeat. The partner application is reviewed; sending it does not approve payouts. Referral credit and withdrawable partner earnings are different. Previous credit rewards do not become withdrawable because an application is approved. Check the current dashboard before converting eligible earnings or requesting a payout. # Renewals and expiry (https://docs.layerbeat.com/guides/renewals) A VPS is prepaid for a fixed term. Check `expires_at` on the server and keep enough available credit in the currency you will use for renewal. ## Renew manually [#renew-manually] Any member with server write access can renew using **their own** personal credit. An API key charges its creator. Read the current renewal settings and available term prices first: ```bash curl -sS "$BASE/v1/vms/$VPS_ID/renewal?currency=USD" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Submit the selected term, currency and spending limit: ```bash export RENEW_REQUEST_ID=$(uuidgen) curl -sS -X POST "$BASE/v1/vms/$VPS_ID/renew" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $RENEW_REQUEST_ID" \ --data '{"term_months":1,"currency":"USD","maximum_amount":"YOUR_REVIEWED_LIMIT"}' ``` Replace the limit with a numeric string equal to or above the reviewed term price. `maximum_amount` is a ceiling, not an instruction to charge that amount. For IDR, use a whole-Rupiah string. Poll the returned operation. `202` reserves credit and begins processing; it does not confirm that the expiry has already changed. A definitive failure before submission releases the hold. An uncertain submission keeps it while the existing renewal is reviewed. ## Renewal pricing [#renewal-pricing] Where a term and currency have a purchase-time price lock, renewal uses that locked price, including a discount in effect when the server was purchased. Other terms or currencies use the published renewal price. Read the renewal response rather than inferring the price from a current new-server plan. ## Enable automatic renewal [#enable-automatic-renewal] Automatic renewal is off by default. Only the original purchaser can enable or disable charges from their credit. Save the term, currency and maximum amount using the console or `PUT /v1/vms/{id}/renewal`. Attempts begin **48 hours before expiry**. Each attempt checks the saved consent, current write access, verified eligibility and available balance. USD and IDR are never combined. Saving consent alone does not submit a renewal. Changing your default billing currency does not change existing consent. Update the renewal policy explicitly if you want to use another balance. Check `renewals_enabled` to see whether new renewals are currently admitted. ## Expiry and grace [#expiry-and-grace] The renewal response includes `renewal_deadline`, normally eight days after expiry for a Layerbeat-purchased VPS. Renewal during grace is subject to the server still being recoverable. No new renewal is accepted at or after that deadline. Layerbeat schedules reminders before expiry and during grace. Check your account email and available credit; an email is not proof of a successful charge. When the Layerbeat service closes after grace, it is shown as **Deleted from Layerbeat** and management and renewal are blocked. This local closure is distinct from an explicit infrastructure deletion and does not assert that disks have been physically erased. Keep your own backups before expiry. If a renewal is pending or uncertain, check its operation before attempting another order. For errors and support details, see [troubleshooting](/guides/errors). # SSH keys and passwords (https://docs.layerbeat.com/guides/secure-access) Set the login method when creating a VPS. SSH keys are the default; password methods do not require SSH keys. Generate an Ed25519 key if you do not already have one: ```bash ssh-keygen -t ed25519 -C 'layerbeat' ``` Add the contents of `~/.ssh/id_ed25519.pub` under **Access & keys → SSH keys**. Submit the returned ID in `ssh_key_ids` with `auth: "ssh_key"`. You can select up to ten keys, subject to the combined creation-payload limit. Only upload the **public** key. Keep the private key on your own device. For a key-based Linux server: ```bash ssh -i ~/.ssh/id_ed25519 root@YOUR_SERVER_IP ``` Password login is disabled for this login method. Registering a new workspace key later does not install it on an existing server. Choose **Custom password** in the console, or send `auth: "custom_password"` and `password` in the creation request. Omit `ssh_key_ids`. Use 12–30 ASCII characters with at least three categories: uppercase letters, lowercase letters, digits and supported symbols. The allowed symbols are: ```text ()`~!@#$%^&*-+=_ ``` Spaces are not accepted. Save the password in your password manager: Layerbeat does not return a custom password in server details. Choose **Random password**, or send `auth: "random_password"` and omit both `password` and `ssh_key_ids`. Layerbeat generates the initial password. After provisioning succeeds, retrieve it from the server's access controls or `POST /v1/vms/{id}/password/reveal`. Only the original purchaser or their API key can retrieve it, even if someone else owns the workspace. The generated credential is available for **24 hours after successful provisioning**, or until explicitly forgotten. Save it securely, then use `DELETE /v1/vms/{id}/password` to remove the stored copy. Forgetting it does not change the password on the server. ## Browser console [#browser-console] The server management page can open a browser console when available. `POST /v1/vms/{id}/console` provides temporary console access and requires write permission. Treat a console URL as a credential: do not share it or include it in logs. It is separate from your SSH or password login method. If you cannot connect, confirm the VPS is running, use its current public IP and check both [cloud firewall rules](/guides/networking) and any firewall inside the operating system. # Create and manage a VPS (https://docs.layerbeat.com/guides/servers) A VPS belongs to your selected workspace. The user placing the order pays from their own credit; an API key charges its creator. ## Prepare a purchase [#prepare-a-purchase] Choose an available [location, image and plan](/guides/catalog), a prepaid term and a [login method](/guides/secure-access). Use a server name of up to 63 characters, starting with a letter or number and containing only letters, numbers, `.`, `_` or `-`. In the console, **Review & Purchase** shows your configuration, term, currency and total. Through the API, request a quote and review `total` and `wallet.shortfall` before submitting an order. | Purchase field | Use | | --- | --- | | `name` | Your server's name | | `region`, `plan`, `image` | IDs from the current catalog | | `term_months` | An available prepaid term: 1, 3 or 12 months | | `currency` | `USD` or `IDR`; selects one personal balance | | `quote_id` | A matching, unexpired quote | | `auth` | `ssh_key`, `custom_password` or `random_password` | | `ssh_key_ids` | Required for key-based login; omit for password login | | `auto_renew` | Explicit automatic-renewal consent; defaults to `false` | The [quickstart](/guides/quickstart) includes a complete key-based purchase request. ## What happens to your credit? [#what-happens-to-your-credit] ### The total is reserved [#the-total-is-reserved] Layerbeat checks the configuration and available credit, then records the server and provisioning operation. The order amount becomes a hold in your selected balance. ### Provisioning runs in the background [#provisioning-runs-in-the-background] `POST /v1/vms` returns `202` with `vm` and `operation`. Follow the operation until it finishes. Wait for successful setup before connecting. ### The result is confirmed [#the-result-is-confirmed] Successful provisioning settles the reserved amount as a charge. A definitive failure releases the hold. If the external result is uncertain, the hold remains while Layerbeat reconciles the original order. An insufficient balance returns `402 insufficient_balance` without creating a server or operation. Top up separately, then retry the purchase. Use the [same idempotency key](/guides/idempotency) when retrying an uncertain request. ## Read and manage a server [#read-and-manage-a-server] ```bash curl -sS "$BASE/v1/vms/$VPS_ID" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" curl -sS -X POST "$BASE/v1/vms/$VPS_ID/reboot" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Start, stop and reboot each return an asynchronous operation. A stopped VPS keeps its prepaid subscription and expiry; stopping it does not pause billing. | Server status | What to do | | --- | --- | | `provisioning` | Follow the creation operation | | `running` / `stopped` | Manage the server normally | | `starting` / `stopping` / `rebooting` | Wait for the current power operation | | `suspended` | Check expiry and whether renewal is still available | | `terminating` | Wait for an explicit deletion to finish | | `terminated` | The Layerbeat service is closed; inspect `termination_reason` | | `failed` | Read the operation error and check the wallet's hold | ## Delete a server [#delete-a-server] Deletion permanently removes the requested infrastructure and its data. Take any backups you need first. In the console, enter the exact server name to confirm; the API also requires it: ```bash curl -sS -X DELETE "$BASE/v1/vms/$VPS_ID?confirm=agent-01" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` Track the returned deletion operation. Subscription expiry is a separate process; see [renewals and expiry](/guides/renewals). # Pay with USDC (https://docs.layerbeat.com/guides/top-up-layerbeat-credit-with-usdc) USDC top-ups add USD credit. They do not fund IDR credit, convert an existing balance or purchase a VPS. Start by checking the enabled networks: ```bash curl -sS "$BASE/v1/billing/payment-methods" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` ## Create a Solana top-up [#create-a-solana-top-up] Use a verified account and a key with `billing:write`. Save one request identity for the entire attempt: ```bash export TOPUP_REQUEST_ID=$(uuidgen) curl -sS -X POST "$BASE/v1/billing/top-ups" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $TOPUP_REQUEST_ID" \ --data '{"method":"usdc_solana","currency":"USD","amount":"25.00"}' ``` The response records your payment ID, expiry, network, accepted USDC mint, recipient, exact token amount and `payment_uri`. Always use these returned instructions; do not reuse an address or QR copied from an old guide. ### Open the payment [#open-the-payment] Use the QR, wallet link or connected-wallet controls on the Layerbeat payment page. A compatible Solana Pay wallet includes the payment reference automatically. ### Check and approve [#check-and-approve] Confirm the network, USDC token, recipient and exact amount in your wallet. A direct Solana wallet transfer also needs SOL for network fees. Devnet payments use test tokens; they do not represent a mainnet payment. ### Wait for confirmed credit [#wait-for-confirmed-credit] Layerbeat checks the finalized transfer before credit becomes available. Keep the payment page open, or poll the payment and wallet through the API. ```bash curl -sS "$BASE/v1/billing/payments/$PAYMENT_ID" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" curl -sS "$BASE/v1/billing/wallet" \ -H "Authorization: Bearer $LAYERBEAT_API_KEY" ``` ## Why the exact amount matters [#why-the-exact-amount-matters] An instruction can include a small fractional-cent suffix to identify the top-up. Send the full displayed USDC amount and preserve its reference. The suffix is retained as fractional credit, rather than being a service fee; whole USD cents are available to spend. Only the stated native USDC token on the stated network is accepted. Other tokens, networks or bridged assets cannot be assumed to count as payment. ## Delayed, partial or duplicate payments [#delayed-partial-or-duplicate-payments] Attributed partial and excess transfers add the confirmed amount to your credit. A late transfer can still add credit while the original intent remains expired. The ledger and payment's `received` fields show what was credited. If your wallet reports an uncertain submission, check its original transaction and the existing Layerbeat payment before sending again. Repeating a top-up request with the same idempotency key retrieves the original intent; it does not undo a second transfer you authorize separately. If credit does not appear after finality, contact support with the payment ID and transaction signature. Never share a seed phrase or private key. # Pay in Rupiah with Doit (https://docs.layerbeat.com/guides/top-up-with-doit-idr) Doit is Layerbeat's primary Rupiah gateway when enabled. Pay in IDR to add the exact amount to your personal IDR credit. Layerbeat covers processing fees; this does not exchange your USD balance. ## Choose a payment option [#choose-a-payment-option] In the console, select a Rupiah top-up, enter an amount and choose QRIS or an available bank. The payment page shows instructions and an **Open secure payment page** link for the same top-up. For an integration, read `GET /v1/billing/payment-methods`. Use Doit's returned `checkout_options` rather than assuming every bank is enabled. Create a top-up with a durable idempotency key: ```json { "method": "doit", "currency": "IDR", "amount": "100000", "payment_option": { "method": "qris" } } ``` Scan the returned QR using a QRIS-compatible banking or wallet app. Confirm the amount before approving payment. Choose a bank from the API's available options. For example, when Mandiri (`bmri`) is offered: ```json { "method": "doit", "currency": "IDR", "amount": "100000", "payment_option": { "method": "virtual_account", "bank": "bmri" } } ``` Use the displayed bank, account number and total. Instructions belong to this payment; do not reuse another invoice's account number. Omit `payment_option` to let the customer choose an available method on Doit's hosted page: ```json { "method": "doit", "currency": "IDR", "amount": "100000" } ``` Open the returned `checkout_url`. If checkout submission is still uncertain, the response can be `202` without a URL. Keep the same intent and recover its original checkout. ## Submit through the API [#submit-through-the-api] Send your chosen JSON body to `POST /v1/billing/top-ups`, with `Authorization`, `Content-Type: application/json` and `Idempotency-Key`. Amounts are whole-Rupiah strings without periods or separators. Native instructions are returned in `checkout_details` only after their amount and fee policy are verified. If no verified instructions are available, do not infer payment data from missing fields. ## Confirm payment [#confirm-payment] Poll `GET /v1/billing/payments/{id}`. A browser return to Layerbeat is not payment confirmation. Layerbeat verifies the gateway's authenticated status before applying credit once. You can request a status refresh with `POST /v1/billing/payments/{id}/refresh`. Use the original payment ID if checkout creation was uncertain; do not create a second invoice with a new key to recover the first. If the gateway for new top-ups changes, existing invoices remain attached to Doit. Refunds, reversals and mismatched settlement evidence require review. For personal balances and transaction history, see [credit and billing](/guides/money). # Windows servers (https://docs.layerbeat.com/guides/windows) Layerbeat sells English Windows Server 2016, 2019, 2022 and 2025. The Windows licence is included in the plan price. ## Choose a Windows plan and image [#choose-a-windows-plan-and-image] Windows runs only on Windows plans, and Windows images only on Windows plans. In the catalog, both have `os: windows`; Windows plan names use `W`, for example `SG-W225`. ```bash curl -sS 'https://layerbeat.com/v1/plans?region=sgp' | jq '.data[] | select(.os=="windows") | {id, name, memory_mb, disk_gb}' curl -sS 'https://layerbeat.com/v1/images?region=sgp' | jq '.data[] | select(.os=="windows") | {id, name, min_memory_mb, min_disk_gb}' ``` Windows Server needs at least 2 GB RAM and 50 GB of system disk. Smaller plans are refused. ## Log in with a password [#log-in-with-a-password] Windows servers use password login as `Administrator`; SSH keys are not accepted. Purchase with `"auth": "random_password"`, or `"auth": "custom_password"` with your own `password` (which must not contain `Administrator`). ```json { "name": "win-1", "region": "sgp", "plan": "bv-sgp-...", "image": "windows-server-2022", "term_months": 1, "currency": "USD", "quote_id": "q_...", "auth": "random_password" } ``` After the server is running, read a generated password with `POST /v1/vms/{id}/password/reveal`. It can be retrieved for 24 hours. See [SSH keys and passwords](/guides/secure-access). ## Connect [#connect] Connect with a Remote Desktop client to the server's `ipv4` on port 3389, user `Administrator`. Network Level Authentication is on. A new Windows server takes a few minutes longer than Linux to become ready: setup configures Remote Desktop and the firewall and restarts the server once. ## Firewall and disks [#firewall-and-disks] - Remote Desktop (3389) is open by default. Change it with the server's [firewall rules](/guides/networking). - Inside Windows, inbound traffic from private network ranges is blocked by a Windows Firewall rule group named "Layerbeat isolation". - [Disks](/guides/disks) attached to a Windows server are formatted NTFS and mounted as folders at `C:\mnt\`. # Layerbeat documentation (https://docs.layerbeat.com/) Layerbeat gives you a VPS with root access, a public IP and a firewall. Choose a region, fund your personal credit and deploy a machine for your project or AI agent. Follow the console and API setup, from account creation to your first SSH connection. Create a scoped key and manage machines from your application. Understand USD and IDR balances, stablecoin payments and local checkout. Set spending limits, handle asynchronous work and fund credit with x402. ## How Layerbeat works [#how-layerbeat-works] ### Set up your account [#set-up-your-account] Verify your email, choose a billing currency and name your workspace. A workspace holds shared servers; credit belongs to each user. ### Add personal credit [#add-personal-credit] Pay with USDC on an enabled network to fund USD credit, or use a Rupiah payment method to fund IDR credit. Wait for the payment to be confirmed before purchasing. ### Choose and deploy a VPS [#choose-and-deploy-a-vps] Select a location, image, plan, login method and prepaid term. Review the total in your chosen currency, then purchase using available credit. ## Choose your workflow [#choose-your-workflow] | Workflow | Start here | | --- | --- | | Console | [Account setup](/guides/account) and [VPS creation](/guides/servers) | | Terminal | [Command-line tool](/cli) | | Application | [Authentication](/guides/authentication), [idempotency](/guides/idempotency) and [operations](/guides/asynchronous-operations) | | AI agent | [Agent integration](/guides/agents) | The API base URL is `https://layerbeat.com`. The [endpoint reference](/api/catalog/listRegions) describes request fields, responses and permissions. The complete contract is available as [OpenAPI](https://layerbeat.com/openapi.yaml). ## Manage your machines [#manage-your-machines] Choose a login method and keep server credentials private. Open the ports your application needs. Read the last 24 hours of performance data and grant access. Renew manually or set an automatic renewal limit.