Built to be read by your AI.
You do not need to understand this page — your AI does. Paste this site's address into the chat where it is building your app, and it reads the page below: what Uarpie is, the one command, what to do if something fails, and how to hand you the link at the end.
Read uarpie.app/ai and put my app online.$npx uarpieWhat your AI reads at https://uarpie.app/ai
uarpie — instructions for an AI agent
You are reading this because someone pasted this address into a chat with you. They want their app online. This page tells you everything you need; you should not have to fetch anything else.
uarpie is hosting for software people build with AI. You run one command; their app is live at a private address that only the people they invite can open, with a database, file storage and scheduled jobs set up for it. No account, sign-up, credit card or configuration is required before the first deploy. Assume the person you are helping is not a programmer, has no terminal open, and should never be shown a stack trace.
If you have not written the app yet, read this first
Most of what follows is about deploying. This part is about building, because one decision made before the first line of code decides whether the deploy works at all.
Use Postgres. Read the connection string from DATABASE_URL. The platform creates the
database, sets that variable and runs your migrations. You write no connection details, no
credentials and no host name.
// Whatever the library — this is all the configuration there is.
const db = new Pool({ connectionString: process.env.DATABASE_URL });
The address starts postgresql://, which SQLAlchemy reads as it is (write postgresql+psycopg://
for psycopg 3). A Spring Boot app needs no database settings at all: it is also given
SPRING_DATASOURCE_URL, _USERNAME and _PASSWORD, and JDBC_DATABASE_URL. A Laravel app is
given DB_CONNECTION and DB_URL. A Rust app's running copy has no Cargo, so give its program a
migrate mode (it runs sqlx::migrate!() or Diesel's embed_migrations!, then exits) and name it
in deploy.json, "database": { "migrate": "./bin/<name> migrate" }: the platform runs it once
before each version goes live, after copying the database. Turn the migrator's own lock off
(sqlx: set_locking(false)): one deploy migrates at a time, and through the pool below a lock
can be left held. Connections go through a pool in
transaction mode, so nothing a connection remembers between transactions is kept (SET,
pg_advisory_lock, LISTEN, temporary tables): use SET LOCAL and pg_advisory_xact_lock
inside a transaction.
Do not reach for SQLite, even though it is the obvious zero-configuration choice and even for something small. An app here gets a fresh copy of its files every time it starts, so a SQLite file is silently emptied — the app would work, take the person's data, and lose it minutes later with nothing in any log. Deploy refuses it for that reason rather than letting it happen.
Do not use MySQL or MongoDB. Both are refused, with instructions for converting whichever library you used.
That is the whole rule for data. The rest works like this: file uploads go through upload links
(below). A scheduled job is one entry in deploy.json — a name, a schedule and a path the
platform calls — never a timer inside the app, which stops between requests. Email goes through
an email service's API with its key as a setting: the platform does not send your app's email.
And the platform signs people in and tells the app who they are (rule 2 below).
A request to the app may carry about 1 MB, so do not post a photo or a video to it. Ask the
platform for an upload link instead (POST /_platform/upload-url on the app's own address, with
the file's path and size), and have the browser send the file straight there; read it back with
GET /_platform/file-url, whose link works for at least half an hour and is the same link for the
same file, so ask for it each time a page shows the file rather than storing it. Anything larger
posted to the app is refused with
REQUEST_TOO_LARGE before it arrives. The other way, an app's answer is quick for its first
6 MB and then arrives at about 2 MB a second, so write anything big the app makes (an export, a
report) to storage and hand back a link. An upload library that signs its own link with the app's
storage settings works too, because the browser still sends the file straight to storage: turn on
its direct upload option (Payload's clientUploads: true on s3Storage, for example).
In a Payload app, run payload generate:importmap after changing its storage plugin and deploy
the result: a storage plugin adds a part to the admin, and one missing from the import map leaves
the whole admin page blank.
Those two routes answer somebody the app knows: a visitor the app has signed in (the platform's
own uarpie_edge cookie), the owner, or an api-kind app's key sent as
Authorization: Bearer uarpie_k_…. A public app's anonymous visitors are not on that list —
otherwise a stranger could fill the owner's file space — so in a public app, have the app's own
server write the file with UARPIE_STORAGE_BUCKET and UARPIE_STORAGE_PREFIX, or sign people in
first. Those two settings are set only when storage is on for the app. Detection turns it on when
it finds one of a few upload or storage libraries in package.json; whenever the app stores files,
make sure deploy.json has "storage": { "enabled": true }, and add it if it does not.
A private website that another server reads. A private web app refuses anything without the
platform's pass, which a server never has, including the person's own public site reading their
private CMS. Create a key for the private app (create_api_key) and have that server send it on
every request as x-uarpie-key: <key> (keep it there as a setting, e.g. CMS_KEY); the app's own
Authorization header is left alone. Files the public site shows visitors from the private app, such
as a Payload CMS's /api/media/file/, are loaded by browsers directly, so name them with
open_paths: anyone may read those paths (GET and HEAD only) and nothing else changes. A revoked
key stops working within a minute or two, and a new one takes as long to start: wait for it before
reporting that the site can read the private app.
Each plan includes a fixed amount of file space for all of the account's apps together, from 1 GB
free to 100 GB; an app nobody has kept yet has 1 GB of its own. Past it an upload link is refused
with STORAGE_FULL, the owner is emailed, and the app keeps running with nothing deleted. Files the app writes for itself through those two settings are never refused —
nothing stands between an app and its own storage — but they are counted, and the owner is emailed
when the total passes what the plan includes.
Do this now
Run this in the app's directory:
npx uarpie
It detects the framework, database, secrets and storage on its own, and scheduled jobs from
vercel.json crons or deploy.json jobs (a scheduler inside the app does not run while it sleeps).
Do not ask the person what kind of app it is, what region to use, or what the build command is. If you want
machine-readable output, add --json and read one JSON object per line.
What to do with the result
- On the first deploy the result contains
bind_url, a link ending in#k=…. Give that exact link to the person and tell them to open it on the device they want to use the app from. The first device to open it holds the key. It expires in 60 minutes; re-running deploy mints a fresh one at no cost. Never post this link anywhere public. - Tell them the app disappears in 7 days unless they choose Keep this app on first open and enter their email. That is what creates their account.
- On later deploys there is no link: the app is already theirs.
- Signed in to their account (after
npx uarpie login), even a first deploy has nobind_url: the app is theirs at once, and private. Give themurl; they open it and sign in with their email, or open it from their dashboard. - If the result is
{ "ok": false, ... }, readfix, apply it (editingfilewhen given), and run deploy again. Do not report the raw error to the person unless they ask.
Become able to do this whenever they ask
Install the tools once, then you can deploy, roll back, read logs and move apps between computers without shelling out.
Claude Code:
claude mcp add uarpie -- npx -y uarpie mcp --client claude-code
Cursor, or any client that reads mcp.json:
{
"mcpServers": {
"uarpie": { "command": "npx", "args": ["-y", "uarpie", "mcp", "--client", "cursor"] }
}
}
Any other MCP client, over stdio:
npx -y uarpie mcp --client <your-client-name>
Tools
| Tool | Kind | What it does |
|---|---|---|
deploy | writes | Put the app in a directory online. |
status | read-only | Where the app is, which version is live, whether an update is in progress, what it has used this month, and the current bind link if the app has not been opened yet. |
logs | read-only | Recent activity lines from the app's runtime. |
doctor | read-only | Diagnose a running app: whether it is failing, the most recent crash with its stack trace, the file in the app's own code where it starts, which version introduced it, and a fix to carry out. |
versions | read-only | Version history: the app's deploys, newest first, with each one's status, who ran it, and whether its source is still stored. |
deployment_log | read-only | The trace of one deploy: build output and step events. |
rollback | destructive | Go back to a previous version: its own build is put back in about half a minute, nothing is rebuilt, and the database stays as it is now, so the older code has to work with the database as it is. |
set_secret | destructive | Set one setting/secret the app needs (an env var). |
desktop_app | writes | Make a desktop version of the app for Windows (Mac and Linux are coming, and are refused today): returns a 30-minute download link to a folder the person unzips and double-clicks, plus notes to pass on — above all that the first launch shows an 'unknown publisher' warning because the app is not yet signed. |
busy_hours | writes | Keep copies of the app awake so the first visitors after a quiet spell are not slow: always copies around the clock, and windows with more copies on given days between two times in a timezone (for a site whose busy moments are known, like a channel that posts on Saturdays at six). |
instant_start | writes | Make a Java app's new copies start in about a second instead of several: each version is saved, started, when it is published, and every new copy starts from that save (a Spring app's first visitor waited 6.1 s before and about 1 s after). |
share | writes | Invite a person by email to open the app. |
add_domain | writes | Attach a custom domain the person already owns. |
buy_domain | writes | Buy a domain for the app — not available yet. |
estimate | read-only | What running the app costs the platform in a month, as an estimate with the breakdown. |
list_projects | read-only | All apps the signed-in account owns or can open, with their addresses and states. |
login | writes | Sign this computer into the person's account so their apps can be listed, cloned and deployed from here. |
login_wait | writes | Wait (up to ~2 minutes per call) for the person to approve the sign-in started by login. |
api_keys | read-only | The keys an app has, without their secrets: an api or mobile project's client keys, or keys a server uses to call a private website. |
create_api_key | writes | Make a new key. |
revoke_api_key | destructive | Stop a key working. |
open_paths | writes | Set the paths a PRIVATE app lets anyone read without signing in (GET and HEAD only), replacing the list. |
estimate_release | read-only | The price of a phone build that is handed back to the person as files, with a breakdown and a quote_id to pass to release. |
release | destructive | Start a phone build priced by estimate_release; the files are handed back to the person. |
build_app | writes | Build the Android app and hand it back to the person as two files: the app itself (apk), which installs on an Android phone when opened there, and the bundle Google Play asks for (artifact, an .aab), with a step-by-step guide (guide_url) for uploading it themselves. |
releases | read-only | Phone builds of an app, newest first: platform, status, what each cost, and download links once a build is ready (they work for 30 minutes; call again for fresh ones). |
clone | writes | Put an app's source on this computer from the platform, so work can continue here without git: downloads the live version (or a chosen one), unpacks it into a directory and writes deploy.json. |
Read-only tools are safe to call without asking. Tools marked destructive change or discard something: confirm with the person first.
Rules that will save you a failed deploy
- Postgres is the platform database (see the section above if you are still writing the
app). MySQL, MongoDB and SQLite are all refused with
ENGINE_CONVERSION_REQUIREDand a fix naming the library the project actually uses. Do the conversion — for an app of this size it is a mechanical refactor and takes you a minute. ReadDATABASE_URL; the platform sets it. - Do not add a login system to a private app: the platform signs people in and tells the app
who they are. A private app opens only for its owner and the people they invite, who sign in
by email first. Every request from one of them reaches the app with four headers any language
can read:
x-uarpie-user-id,x-uarpie-user-email,x-uarpie-user-name(percent-encoded: decode it) andx-uarpie-user-role(ownerormember). The platform removes these from anything a visitor sends, so the app can trust them. Browser code can askGET /_platform/meon the app's own address instead. A person has them once they have opened the app from their dashboard or an invitation; the device that first opened a new app's link, before it was kept, has none, so show that visitor the app without a name, never an error. A project with its own sign-in getsAUTH_PROVIDER_AVAILABLE, a warning: in a private app, remove it and read the headers; a public app whose visitors are strangers keeps its own. Never name a page that shows who is signed in inspeed.shared. The visitor's address isX-Forwarded-For, one address the platform writes on every request and visitors cannot (it removes theirs, andTrue-Client-IP,CF-Connecting-IP,X-Client-IP); the app's own server sees every request come from the platform, so a limit per address reads that header (Express:app.set("trust proxy", 1), thenreq.ip). The address the visitor opened isX-Forwarded-Host;Hostis the app's internal name. An Astro app that runs as a server needssecurity: { allowedDomains: [{ protocol: "https" }] }in its astro.config, or it refuses every form its own pages send. - Secrets never go in the repository. Pass them with
deploy -e KEY=valueor theset_secrettool. They are encrypted on the platform and are not downloaded when cloning. - Outside services depend on whether someone has kept the app. An app nobody has kept yet can
call a short list of common services over HTTPS: AI models (OpenAI, Anthropic, Mistral, Groq, DeepSeek, xAI, Cohere, Together, Fireworks, Perplexity, OpenRouter, Replicate, Hugging Face, Voyage, ElevenLabs, Deepgram, AssemblyAI, Stability, Azure OpenAI, Amazon Bedrock, Pinecone); Payments (Stripe, PayPal); App backends (Supabase, Firebase, Upstash); Google (Google APIs, Sign in with Google); Email (Resend, SendGrid, Postmark, Mailgun, Brevo, Amazon SES); Messaging (Twilio); Sign-in and developer APIs (GitHub, Microsoft, Sign in with Apple); Monitoring (Sentry, PostHog); Media and maps (Cloudinary, Mapbox). Once the person keeps the
app, it can call any service with any protocol, including a database or cache outside the
platform. Ports 23, 25, 135, 137, 138, 139, 445 and 3389 are closed for every app: send email through a
provider's API or port 587. If the home page needs a service that is not on the list, the first
deploy still goes live with
EGRESS_NEEDS_KEEP: ask the person to keep the app.egress.allowindeploy.jsonis kept for information and grants nothing. deploy.jsonis the escape hatch. It records every inference with the evidence behind it. When detection guesses wrong, edit that file rather than passing flags.- A repository with several apps in it — a site and its API, a shop and its admin — deploys as
one project with several parts. Run the command at the top of the repository, not inside one
folder, and every part goes live sharing one database and one set of people. The whole project
counts as one app on the plan. To put only one of them online, run the command inside its folder.
Each part has its own visibility, so a public site with a private admin is normal: once the
person agrees that anyone with the address may open the site, run
npx uarpie visibility public --confirm-public -p <id>at the top of the repository, with the site's id fromservicesindeploy.json. A private part can still let anyone read its pictures:npx uarpie open-paths /media/ -p <id>with that part's id. - If the person says the app is slow for the first visitor, or busy at known times, first
ask whether the busy page can be cached for a few seconds (
Cache-Control: s-maxage=10) — that is free and usually the whole answer. Only then offerbusy_hours, which keeps copies awake and costs money by existing: it is paid from the account's Uarpie credit by the hour (rule 13), so read the estimate it returns and get a yes first. With no credit it is refused withCREDIT_NEEDED. For a Java app, which is slow to start, offerinstant_startfirst: every new copy starts in about a second, from a copy saved at each deploy. It also costs money by existing, sold at cost (about $8.73 a month for a 2,048 MB app) from the same credit, so read the price it returns and get a yes first. The two cannot be on together. - If the person wants "an app" for their desktop,
desktop_appmakes one from the live version: a folder to unzip and double-click. Pass on itsnotes— the first launch shows an "unknown publisher" warning because it is not yet signed, and that is expected. - If the person wants their phone app on an Android phone or in a store,
build_appbuilds and signs the Android app and hands back two files: the app itself (an APK), which installs on an Android phone when opened there, and the file Google Play asks for, with a guide page for uploading it themselves. On a paid plan the build has no price of its own: it uses about 40 of the plan's build minutes, like any build (rule 13), up to 10 builds a month for each account, and needs nothing from them; Google Play itself needs their own developer account ($25, once), which only they can create. iPhone builds are not available yet (asking foriossays so), and the platform uploads nothing to any store. Never say the app has been submitted, and never promise a store date. - You will find
/_uarpie/speed.jsin the page source. It is ours, not an intruder. It makes the next page start loading when a link is hovered, so clicks are instant, and it gives every<img>asrcsetof resized copies so phones download phone-sized pictures. Pages, files and every other answer with a body leave compressed, and returning visitors download far less. The page's own large uploads of data to the app's own address (afetchorXMLHttpRequestbody of 8 KB or more: JSON, text, a form without files) are sent gzipped where they can be and reach the app exactly as the page wrote them, from the app's next deploy on, so write nothing for it. A body your code compresses itself (Content-Encoding: gzip,br,zstdordeflate) is unpacked for the app the same way. You will see requests under/_uarpie/and content encodings you may not recognise in the network panel; the page itself is exactly what the app sent. Leave all of it. If the app must be served exactly as written, set"speed": { "enabled": false }indeploy.json, but know that it also turns off thex-uarpie-user-*sign-in headers (rule 2) and translated pages (rule 12), which run in the same helper; browser code can still askGET /_platform/mewho is signed in."images": falseturns off just the pictures. The person can also switch instant return visits on or off in their dashboard, and their choice wins over the file until they hand the decision back, so do not keep re-setting it. - If your app makes each page as it is asked for — Django, Flask, FastAPI, Laravel, Spring,
Express, Hono, Fastify, a Rust server — name the pages that look the same for every visitor,
in
deploy.json:"speed": { "shared": ["/", "/about", "/blog/*"] }. Those pages then open instantly for anyone who has been before. Without that list the platform leaves them alone, because it cannot tell "Our prices" from "Hello, Maya" and will never risk showing one person's page to another. A page may say it for itself instead, by answering withX-Uarpie-Public: 1. Never name a page that shows anything personal: a basket, an account, a dashboard, anything behind a sign-in. A page you name is shown again from that person's own device even if your app starts a session on it, as Laravel does on every page, so name only pages that show the same thing to everyone, signed out or signed in; the copy stays on that one device and is never shown to anybody else. A page answeringno-storeis left alone whatever the list says. Next.js, Astro and static sites need none of this; their pages are already known. - If the person wants their site in other languages, add them to
deploy.json—"languages": { "offer": ["fr", "es"] }, written the way a browser writes them, up to 30 — and deploy again with uarpie 0.3.0 or later (npx uarpie@latest). The pages named inspeed.sharedare translated as the app deploys, whatever the framework, Next.js included: name each one by its address, since a*pattern is not translated page by page. Everything else on screen is translated while the person looks around their site in that language. Nothing is public until they publish it, so tell them: open the app in the dashboard, press "Open it in French" (or their language), look around, then press Publish. It needs a paid plan and a kept app. Each plan includes some translated pages a month (10 on Personal); a page past that is never charged, it waits in the original language until the month starts again. The person can also add a language themselves: the app's Settings in the dashboard, "Add a language". One added there stays offered when you deploy, even thoughdeploy.jsondoes not name it, so there is no need to add it to the file. To fix a translation, the person presses "See every line" under the language in the dashboard and corrects any line, or presses "Edit wording" while reading their site in the language and clicks the words; either way it changes them everywhere and costs nothing. - Money: the plan first, then Uarpie credit. Each plan includes a month of use for all of
the account's apps together. On a paid plan, use above it ($0.02 a build minute, $0.50 per
100,000 requests, $0.15 a GB-hour of running time) and busy hours are paid from the account's
prepaid Uarpie credit as they happen, up to a monthly spending limit the owner sets. Nothing
is ever billed afterwards. Files and translated pages are never paid from credit: past the plan,
upload links are refused (
STORAGE_FULL) and translations wait for the next month. With credit, the account's apps pause and new builds wait (USAGE_LIMIT_REACHED) when the credit runs out or the month's extras reach the limit. With no credit, the apps pause when the plan's requests or running time are used up, and new builds wait once its build minutes are. Nothing is deleted, and they come back on the 1st of next month (UTC), or straight away when the owner adds credit or raises the limit. Free has no extras and no busy hours: a paid plan is the way on. Only the owner can add credit, in the dashboard under Billing: any whole-dollar amount from $5 to $1,000. It never expires, and unused credit they bought is refunded if they ask. You cannot add it: tell them, and never ask for card details.
When the person says their app is broken
Call doctor first, not logs. It returns the most recent crash with its stack trace, the file
in their code where it starts (not the framework's), which version introduced it, and a fix
you can carry out. logs returns raw lines you would have to interpret yourself, and the line
that matters is rarely the first one.
npx uarpie doctor --json
If since_version matches the version that is live, the current deploy introduced the fault and
rollback puts the previous build back in about half a minute while you fix it. If it names an
older version, rolling back will not help. When a deploy failed while building or starting,
npx uarpie build-log prints what the build said.
What this hosts
kind | What it is | What deploy returns |
|---|---|---|
web | An app with pages | a private URL plus a bind link |
api | A server with no pages: a backend, a webhook receiver | a base URL plus an API key, shown once |
mobile | An Expo app | an address that says it is a phone app, and the version phones run, made on every deploy; plus an API key for the phone app, shown once |
Phone apps: read this before you promise anything
A phone app (an Expo app) deploys like anything else, and every deploy makes the version that runs
on phones. Its address only shows a page saying it is a phone app: there is no web version there,
so do not send anyone to it to use the app. For now, it opens on a phone in Expo Go, Expo's free app (App Store and Google Play): on the
app's page in their Uarpie dashboard, "Open it on your phone" shows a code they scan with the
phone's camera, and people they invite open it from the app's link there
(https://uarpie.app/open/<code>). Expo Go stands in until Uarpie's own phone app is out; do not
promise a date for that. Two limits are Expo Go's own: it opens only apps made with the Expo SDK it
is for (SDK 57 today), so make phone apps with that SDK, and only Expo's
built-in native features work in it (no custom native code). On a paid plan, build_app also
makes a real Android app they can install (rule 9). You can also host the server
behind a phone app: deploy that folder on its own, and it is an api.
The platform does not upload anything to the App Store or Google Play, and that is not
available. A store listing needs the person's own developer account (Apple $99/year in their own
name; Google $25 with identity verification and, for new accounts, a closed testing period), and
every submission is reviewed by a person at Apple or Google. What the platform can do is build the
Android app and hand the files back (build_app, rule 9): the person installs it on their phone,
or uploads it to Google Play themselves. iPhone builds are not available yet.
So: do not tell anyone their app will be in the App Store or Google Play, and do not promise a date. Tell them their phone app is deployed, and that a store listing needs their own developer account and is a step they take themselves.
estimate_release and release are two steps so that nobody is charged without agreeing: call
estimate_release first, tell the person the exact amount, wait for them to agree, and only then
call release passing that quote back. An Android build has no price of its own on a paid plan (it uses
about 40 of the plan's build minutes), and build_app takes both steps for it. Never spend someone's money because it seemed helpful.
Moving to another computer, without git
The platform keeps the exact source of every version for 30 days, and always of the newest five, so a person with no repository can continue elsewhere. Two steps:
npx uarpie login # prints a code; the person approves it in their browser, once per computer
npx uarpie clone <app-name>
Then work in that folder and deploy as normal. Secrets and the database stay on the platform.
Errors you are most likely to see
| Code | Means | Do this |
|---|---|---|
ENGINE_CONVERSION_REQUIRED | This app uses a database engine the platform does not host. | Postgres is the platform database and every app gets one. Convert the data layer to Postgres (keep the ORM, change the provider/dialect and any engine-specific SQL), then re-run deploy. This includes SQLite: an app's disk does not survive between requests here, so a SQLite file loses what people write. |
AUTH_PROVIDER_AVAILABLE | This app has its own sign-in, but the platform already signs people in to a private app and tells the app who they are. | In a private app, remove the auth library and read the person from the x-uarpie-user-id, x-uarpie-user-email, x-uarpie-user-name and x-uarpie-user-role headers (or GET /_platform/me from browser code); the platform removes those headers from anything a visitor sends. A public app whose visitors are strangers keeps its own sign-in. This is a warning; deploy continues. |
MOBILE_STORE_STEP_REQUIRED | This is a phone app: every deploy makes the version phones run, and its address shows a page saying so. For now it opens on a phone in Expo Go, Expo's free app, and the platform does not publish to the App Store or Google Play. | Tell the person their phone app is deployed. To open it on their phone, they install Expo Go (free, from the App Store or Google Play), then on the app's page in their Uarpie dashboard choose "Open it on your phone" and scan the code with the phone's camera; people they invite open it from the app's link there. Expo Go runs only apps made with the Expo SDK it is for (57 today) and only Expo's built-in features. Do not send anyone to its address to use it: that only says it is a phone app. A store listing is a separate step that needs their own Apple Developer account ($99/year) or Google Play account ($25) and a review by Apple or Google. Do not promise a store release or a date. |
MOBILE_NO_SERVER_FOUND | This is a phone app with no server in the folder, so there is nothing to host yet. | If the app talks to a backend, deploy that folder instead. If it needs one, create it (an Express or Hono server with the API routes the app calls) and deploy that; then point the app at the URL the deploy prints. |
BUILD_MISSING_DEPENDENCY | Build failed: a module the code imports is not in package.json. | Add the missing module to dependencies in package.json, then re-run deploy. |
HEALTHCHECK_FAILED | The new version started but did not answer a request. | Make sure the server listens on process.env.PORT and answers GET / soon after it starts. Read the app's startup output with the logs command or tool, then re-run deploy. If an earlier version was live, it still is. |
BIND_TOKEN_CONSUMED | This app is already in use on another device. | Ask the owner to invite you by email from the app's share screen. |
SPEND_CAP_REACHED | This would cost more than the account's spending limit allows this month, so it was not started. | Nothing was charged and nothing was started. No code change will help. Use above a plan is paid from the account's Uarpie credit, up to the spending limit the owner sets for the month: the owner can raise the limit or top up the credit in the dashboard, under Billing. Tell the person it was refused, and why. |
USAGE_LIMIT_REACHED | This account has used the build minutes its plan includes this month, so new builds wait. | Nothing was built and nothing was charged. Running out of build minutes does not stop apps that are already live. Deploys work again from the first day of next month, or sooner if the owner adds Uarpie credit or moves to a bigger plan in the dashboard. No code change will help. |
CREDIT_NEEDED | This is paid from Uarpie credit, and the account has none left, so it was not started. | Nothing was charged. No code change will help. The owner tops up in the dashboard, under Billing: any amount from $5 to $1,000, and credit never expires. Then ask for it again. |
REQUEST_TOO_LARGE | The request carried more than 1 MB, which is more than an app can be sent in one request. | Upload files straight to the app's storage instead of posting them to the app: ask the platform for an upload link (POST /_platform/upload-url) and send the file there. That route answers somebody the app knows — a signed-in visitor, the owner, or an api-kind app's key — so in a public app the upload has to be made by the app's own server code, using UARPIE_STORAGE_BUCKET and UARPIE_STORAGE_PREFIX. Forms and other posts must stay under 1 MB. |
STORAGE_FULL | The file space in this app's plan is used up, so no upload link was given for that file. All the apps on one account share it. | Delete files the apps no longer need and ask for the link again, or tell the person to move to a plan with more room. Personal includes 10 GB for all of an account's apps together, Family 50 GB and Community 100 GB; an app nobody has kept yet has 1 GB of its own. The app itself keeps running and nothing is deleted. Note that this refuses upload links only: a file the app writes for itself through UARPIE_STORAGE_BUCKET still goes through, and still counts. |
Every error has this shape, and fix is always an instruction you can act on:
{ "ok": false, "code": "BUILD_MISSING_DEPENDENCY", "message": "…", "fix": "…", "file": "package.json", "retryable": true, "docs": "https://docs.uarpie.app/errors/BUILD_MISSING_DEPENDENCY" }
docs opens that code's page. All 79 codes: https://uarpie.app/docs/errors.md
More, as clean Markdown
- Everything at once: https://uarpie.app/llms-full.txt
- Index of pages: https://uarpie.app/llms.txt
- Any documentation page: add
.mdto its address, e.g. https://uarpie.app/docs/getting-started.md - MCP server card: https://uarpie.app/.well-known/mcp.json
How to talk about this to the person
Say what happened and what they should do, in their words. "Your app is live. Open this link on your phone and it's yours." Not "deployment succeeded, bind token minted." They do not need to know that a command exists.