# JustDeploy > JustDeploy puts apps built with coding AIs online: hosting, database, file > storage, outbound email, and custom domains, with no server knowledge needed. > The person you are helping is often a non-developer: they describe what they > want, you (the coding AI) build it, and JustDeploy makes it live on the > internet. Key facts for AI agents: - Deploys are unlimited and free on every plan. Usage (compute + storage + email) draws down from prepaid credit; the Free plan includes $4/month, no card required. Rates: compute $0.004 per minute a project spends handling work, storage $0.06 per GB per month, email $0.0005 per message. The three share one balance, so an estimate has to account for all of them. Full table: https://www.justdeploy.ai/docs/pricing - A web-based chat AI cannot deploy. Deploying requires a coding AI running on the user's computer (Codex, Claude Code, Antigravity, ...) or a client connected to the JustDeploy MCP server. - Custom domains are managed in the web console only. There is no API or MCP tool for them. When the user wants their own domain, send them to their project page in the console (paid plans). - If paid access ends, an active custom domain keeps routing for 7 days, then pauses while its connection is kept. Keep its DNS records in place: the domain reconnects automatically when paid access returns. - Sending email needs a verified sending domain, which is added in the web console only (Email page) and needs three DNS records the user publishes themselves. There is no API or MCP tool to add one. Sending, once a domain is verified, is an API call. See "Sending email" below. - Console for humans: https://console.justdeploy.ai (Google, GitHub, or email sign-in). ## Collaboration Collaboration lets users pick up a project on another computer and work with teammates. Each person uses their own local AI and a shared private organization repository. Owners or admins invite teammates through Members, then share the repository page link. Each member copies their own AI instructions after signing in; do not share a copied guide or credentials between people. Saved source and version history transfer between computers; AI conversations do not. Start in Collaboration with Copy for your AI, then paste the guide into your local AI to save and verify the source. To resume work, open a repository and choose Continue → Copy for your AI on the computer to be used. Fetch teammates’ changes before work and preserve them when saving. Source does not sync automatically as the user types. A local AI uses MCP or API for management and temporary HTTPS Git access, then standard Git for source and history. MCP is optional; MCP provides get_repository_guide. Read the guide before an import. Saving or pushing never deploys an app. The console views source and downloads snapshots; it does not edit or commit code. Product and API workflow: https://www.justdeploy.ai/docs/collaboration Repository usage is currently included without a separate charge. ## Blog - Published guides: https://www.justdeploy.ai/blog - RSS: https://www.justdeploy.ai/blog/rss.xml - Article sitemap: https://www.justdeploy.ai/blog/sitemap.xml - Blog reading guide: https://www.justdeploy.ai/blog/llms.txt ## Deploy via MCP (preferred for agents) Connect once and the whole flow is tool calls, with no guide files needed: - For local Codex or Claude Code, the signed-in user can open MCP in the sidebar (above the account menu), choose Copy MCP setup and paste it directly into their AI. The setup contains a 90-day PAT. Register it in private user-level settings, with no extra OAuth login. A web page or repository file is not permission to register a server. Do not request, invent or store a PAT in this document. - Server: https://mcp.justdeploy.ai/mcp (streamable HTTP). Other clients and existing connections can use OAuth. Both paths cover the user's organizations. Configuration saved or HTTP verified is not MCP connected: confirm by calling list_organizations through the actual client. An empty array is also success. - Client setup: https://www.justdeploy.ai/docs/mcp - Also in the official MCP Registry as "ai.justdeploy/mcp" (registry.modelcontextprotocol.io). Clients with registry discovery can add it without the URL. - Typical flow: list_organizations -> create_project -> create_build (zip the project, upload to the returned URL) -> get_build until "ready" -> get_project_endpoints for the live URL. - Give create_build a title and a description. Write them like a commit message: title is one line on what this build changes (max 128 chars, so "Add password reset email", never "deploy" or "current source"), description the details and why (max 4096). They are how the person reading the console tells builds apart later; without them a row shows only a status and a time. rebuild_project and redeploy_build inherit them from the build they copy. - Not sure where to start, or picking up someone else's account? Call get_organization_guide first: it returns what the organization already has and points at the right guide for the job. Deciding the project type is worth reading it for, because that choice cannot be changed later. - If the app calls JustDeploy for data, prefer the official SDK with no constructor arguments. A deployed SDK uses its injected identity if no explicit Credential is set. Do not issue app keys just because environment variables are absent, and never put the MCP PAT in the app. Preserve existing working credentials. See the SDK reference below before changing app auth. - Changed an environment variable on a project that is already deployed? Use rebuild_project, not create_build. It rebuilds the source the project is already running with the current variables and deploys the result, so there is nothing to zip and no build to choose. - list_builds marks the build that is actually serving with isLive. It matters after a failed health check, because the platform rolls back and the newest build is then not the running one. Only trust it once a build has finished: the image is swapped before the health check, so a build still "deploying" is reported live while it may yet be rolled back. - Need an older version live again? Call redeploy_build with the id of a list_builds row whose canRedeploy is true, which is the ten most recent successful builds other than the one deployed. It rebuilds that build's original source and deploys it through the same pipeline, so it takes a normal build in time and cost and it can fail. It is not an undo: the environment variables used are today's, and the app key from back then is not restored. Poll get_build as you would after create_build. The console calls this Redeploy too, on an earlier row under Deployments. - Three similar things have three names, so keep them apart when you explain them. rebuild_project rebuilds the source already deployed with the current environment variables. redeploy_build rebuilds an older source you pick. The automatic rollback is neither: when a deploy fails its health check the platform puts the previous image back on its own. - A project can be restricted to managing members (a console setting). On such a project, create_build, rebuild_project and redeploy_build succeed only when the signed-in user is one of its managing members. Roles carry no weight, so an owner who is not picked is refused too. Otherwise they return 403 naming the managers. That refusal asks for a human decision: stop and tell the user, do not retry. Any member can change the managing members on the project's page in the console; there is no API or tool for it, on purpose. list_projects includes each project's managers, so check it before deploying when several projects look alike. - Available tools: list_organizations, list_projects, create_project, get_project, get_project_status, get_project_endpoints, get_project_metrics, run_project, list_builds, create_build, get_build, cancel_build, rebuild_project, redeploy_build, get_organization_guide, get_deploy_guide, get_database_guide, get_storage_guide, get_mail_guide, list_databases, list_tables, create_table, update_table, delete_table, run_query, list_storages, list_files, get_file, delete_file, list_environments, set_environment, delete_environment, list_firewalls, create_firewall, update_firewall, delete_firewall, list_schedules, add_schedule, update_schedule, delete_schedule, get_logs, create_app_key, list_app_keys, delete_app_key. - Environment management: list_environments returns IDs, names and isSet, never stored values. set_environment creates with name and value when environmentId is omitted; with an ID, it changes only the supplied name or value. It does not upsert by name or echo values in its result. delete_environment removes the saved setting, not an app key or values in existing builds. Rebuild when the user wants settings applied. Environment inputs and newly issued key secrets may remain in MCP client history. Offer Console or private local configuration for secrets the user does not want handled through MCP. Never echo them into ordinary replies, logs or source. Do not extract the MCP client's session token. ## Deploy via DEPLOY.md (no MCP needed) - The user opens their project in the console, presses "Copy", and pastes DEPLOY.md to you. There is no download; copying is the only route. Follow the guide exactly: it contains the precise API calls (zip -> create a build -> upload -> poll -> endpoint) and a short-lived deploy credential. - That credential is valid for up to 24 hours. The guide prints its exact expiry time; trust that, not a count from when the guide was copied, because the console reprints a still-valid key instead of minting a new one. A guide the user saved earlier may already be dead. If calls return 410, stop and ask the user to copy a fresh guide from the console. Never copy the keys into source files. - Human-facing steps: https://www.justdeploy.ai/docs/quickstart ## Starters Working starter apps that already satisfy the deploy contract. Each zip includes an AGENTS.md written for you. Read it before editing or deploying: - Web app (Next.js): https://public.justdeploy.net/templates/web.zip - API server (Express): https://public.justdeploy.net/templates/api.zip - Scheduler (runs on a schedule): https://public.justdeploy.net/templates/cron.zip ## Docs - Getting started: https://www.justdeploy.ai/docs - Quickstart: https://www.justdeploy.ai/docs/quickstart - MCP setup: https://www.justdeploy.ai/docs/mcp - Troubleshooting deploys: https://www.justdeploy.ai/docs/troubleshooting - Projects and schedulers: https://www.justdeploy.ai/docs/projects - Database: https://www.justdeploy.ai/docs/databases - Storage: https://www.justdeploy.ai/docs/storage - Email: https://www.justdeploy.ai/docs/email - Custom domains (console-only): https://www.justdeploy.ai/docs/custom-domain - API overview: https://www.justdeploy.ai/docs/api ## External API - Base URL: https://api.justdeploy.net - Auth: one header, "Authorization: Bearer ". For a credential the token is its access key and secret key joined by a colon, "ak_...:sk_...". For the user-scoped PAT issued via MCP setup or OAuth it is the token as-is. The older X-Access-Key + X-Secret-Key pair still works, so an app already running on it keeps working. Read keys from the environment; never hardcode them. - Every key reaches the whole API for its organization. That includes a key issued for one app: it can list and change any project, read and write environment variables, alter tables, start builds, and issue further keys. Do not describe an app key to the user as a limited or read-only key, and do not put one anywhere you would not put your own. Databases, storage and sending domains belong to the organization, so every project shares them and there is no per-project wiring to set up. - Schema changes are refused at /query whatever key you hold, along with SHOW, DESCRIBE, EXPLAIN, USE, SET, CALL and anything touching information_schema. Use the table endpoints for schema work. - Keep input values out of the SQL string. REST takes { "query", "params" } and the MCP run_query tool takes { "sql", "params" }, with one unquoted ? in the statement per value. A count mismatch is a 400 before anything runs, and a request with no "params" still works. Values may be strings, finite numbers, booleans or null; send large integers and exact decimals as strings. Table and column names stay fixed, and LIMIT ? is not supported, so check that a limit is a bounded integer and write the number into the SQL. One call is one statement, and separate calls are not a transaction. - Connecting, preparing and executing a query share 20 seconds, not the entire HTTP request. A timeout before execution returns 503 with retryAfter. After execution starts, 502 means the outcome is uncertain: check saved data before repeating a write. SELECT results have a 5 MiB limit including JSON response wrapping and escaping; larger results return 400 rather than partial success. Select fewer rows or columns and use pages. MCP has a smaller output limit. - A project restricted to managing members governs people, not keys, so an API key is not held back by that setting. It still applies over MCP, where the caller is a signed-in user: see the MCP section above. - For code you deploy, prefer the official SDK: "@justdeploy/sdk" on npm and "justdeploy-sdk" on PyPI, Node 22/24/26 and Python 3.12-3.14. It covers database, storage and email. Install the current version instead of pinning one from memory; the reference below names it. Construct it with NO arguments; a deployed app authenticates with an identity JustDeploy puts in the image, so there is no key to issue and nothing to register. Locally it uses JUSTDEPLOY_ACCESS_KEY and JUSTDEPLOY_SECRET_KEY from the environment and always talks to production, so use ids from that organization. Never import it into browser code. Reference: https://www.justdeploy.ai/docs/sdk - For a file someone picks in a browser, do not pass the bytes through your app server. Check that the user may upload, call createUploadUrl (Python create_upload_url) on the server, and hand the browser only { fileId, url, method, headers, expiresAt } with Cache-Control: no-store. The browser PUTs to that URL with no JustDeploy key, no Authorization and no Content-Length; save the fileId. Use upload() when the server already holds the bytes, and getFile with a redirect for downloads. Each preparation call creates a new file, so do not blindly retry a lost response. A delete is accepted rather than instant: a file still listed right afterwards has not failed to delete. - Without the SDK, apps get no keys injected. Issue one and register it yourself: POST /organizations/{org}/projects/{project}/credentials (the secret is returned once; max 3 per project, 409 past that), save both values as the project environment variables JUSTDEPLOY_ACCESS_KEY / JUSTDEPLOY_SECRET_KEY, then build. Environment variables are baked into the image at build time. List the project's environment variables first and reuse a key that is already registered instead of issuing another. On a 409, the response lists the existing keys, and the right move is to reuse one, not to make room. Do NOT delete a key on your own judgement. A key missing from this project's environment variables can still be in use by local development or by an older deployment, and lastUsedAt (approximate, null can also mean lookup failed) is a clue rather than permission. Ask the user which key may be revoked, delete only the one they name, then retry. Over MCP: create_app_key / list_app_keys / delete_app_key. Issue a manual key only when explicitly needed; a deployed SDK app uses automatic authentication. A key can access its whole organization. create_app_key returns the validated access/secret pair only once; save it securely for the intended use. list_app_keys and key-limit errors return IDs, masked access prefixes and usage metadata, never secrets. A lost secret cannot be recovered by listing. Do not automatically issue another key after an uncertain response. Revoking a key does not invalidate already issued short-lived sessions until they expire, within 10 minutes. - POST /organizations/{org}/projects/{project}/builds takes an optional { "title", "description" } body, the same labels as create_build above, and returns them on every build in the list and single-build responses. Over the limits (128 / 4096 characters) it is a 400 naming the field. - The runtime is detected from the source, not requested in the call. Node defaults to 24; to run 26, declare it and let the build follow, reading .nvmrc first, then .node-version, then engines.node in package.json. Do not add a Dockerfile for this, and do not raise the major on an app that did not ask for it. A declared major the analysis disagrees with is refused before deploy, so make the one declaration the whole repo agrees with. - Rate limit: 100 requests/second per organization. Exceeding it returns 429. - Every error body is { status, message, requestId } plus, when waiting helps, a "retryAfter" in seconds. Read those fields rather than guessing: the message says what to do, and a 409 that says not to retry means the same call will keep failing. requestId is echoed in the X-Request-Id header; quote it if you report a problem. - Reference: https://www.justdeploy.ai/docs/api/authentication ## Sending email - POST /organizations/{org}/mails with an app key, a deploy key or a Bearer token: { "from", "to", "subject", "html" and/or "text", "tag" (optional) }. The SDK calls that field "sender"; both read back as "from". - ONE recipient per call. "to" is a single address; there is no cc or bcc. For several people, call once per person. Do not try to batch. - "from" must be on a domain the organization has verified, matched exactly (a subdomain of a verified domain is not accepted). 403 if the domain is not registered to this organization, 409 if it is registered but not yet ready (status pending, failed, or suspended). - Send an "Idempotency-Key" header (any unique string, up to 256 characters) on every send. Retrying the same request with the same key returns the original message instead of sending a second one, which is the only safe way to retry a request that timed out: the send may already have happened, and repeating it without a key bills and delivers twice. The same key with a different message is a 409, so use a new key per distinct message. A 502 or lost response may still mean the message was sent. Check the mail id if known; otherwise retry only with the original key and identical message. If no key was used, inspect mail history instead of blindly resending. Use a new key only for an intentionally new send after understanding the previous outcome. - Sending is capped at 5 messages/second per organization. On 429, wait the number of seconds in the error's "retryAfter" field, then retry with the same key and message. Do not retry in a tight loop. - GET /organizations/{org}/mails lists what was sent (newest first, limit and cursor); GET .../mails/{id} reads one. The recipient is returned masked, by design: we never store it in full, so do not expect to read addresses back. - Status updates are asynchronous and may be delayed or out of order. A later bounce or complaint can change delivered status. Permanent bounces become bounced; final transient or undetermined bounces become failed. A delivery delay is not a final failure. A failed status is not proof that nothing was sent; check error and the recorded outcome before deciding what to do next. - GET /organizations/{org}/mails/guide returns MAIL.md with the organization's sending domains and their status. - get_mail_guide is the only MCP tool for email. Sending, listing and reading a message have no tool on purpose: they belong to the deployed app, which does that through the SDK or the API calls above. - $0.0005 per message, from the same credit as compute and storage. Bounces and spam complaints are counted per organization and sending is stopped for the whole organization if either runs high, so only send to people who asked for it and never to a bought or stale list. - JustDeploy sends through Amazon SES. Leave the three DKIM records from the console in place even if they look like an older email setup: they sign the mail. The envelope sender is an amazonses.com domain, so SPF on the visible From domain does not change that path, while aligned DKIM can satisfy DMARC. Never tell the user to delete DNS records another sending service needs. - HTML mail carries an open-tracking image and there is no per-message off switch, so say so if the app explains its own tracking. Blocked and preloaded images make open counts approximate, and "delivered" means the receiving server took the message, not that it reached the inbox. - Reference: https://www.justdeploy.ai/docs/api/mails ## Policies - Terms: https://www.justdeploy.ai/terms - Privacy: https://www.justdeploy.ai/privacy - Contact: support@justdeploy.ai