| name | build-monetized-app |
| description | Use when the task is building a new app on Eliza Cloud that earns money — chat apps, agent apps, MCP-backed tools, anything that calls the cloud's chat/messages/inference endpoints on behalf of users. Covers app registration, container deploy, markup configuration, affiliate header, and the survival-economics loop where earnings auto-fund the agent's own hosting. Pairs with the `eliza-cloud` skill (which covers Cloud as a backend in general) by focusing specifically on the build-and-monetize flow. |
Build a monetized app on Eliza Cloud
Use this skill when you need to build an app that takes a markup on every chat or inference call and credits the earnings back to your owner. Eliza Cloud already supports app registration, per-app API keys, container deploys, the appId-based auth and redirect flow, app-scoped chat endpoints, optional affiliate headers, and creator-monetization plumbing — you do not need to invent any of these.
Read references/sdk-flow.md for the 6-step build flow with a self-contained code example. External references (all public):
The survival-economics loop
A Eliza-style agent running in an Eliza Cloud container costs ~$0.67/day at the default tier (256 MB CPU + 512 MB RAM). When the org's credit balance and the owner's redeemable earnings both hit zero, the container is stopped after a 48-hour grace window. The container-billing cron pulls earnings before credits, so an app that earns more than its hosting costs keeps the agent alive indefinitely. See references/survival-economics.md for the exact accounting (redeemable_earnings_ledger, credit_transactions, the cron at app/api/cron/container-billing/route.ts).
This is why the skill exists: making money is how the agent stays online.
Default flow
import { ElizaCloudClient } from "@elizaos/cloud-sdk";
const cloud = new ElizaCloudClient({ apiKey: process.env.ELIZAOS_CLOUD_API_KEY });
const { app, apiKey } = await cloud.routes.postApiV1Apps({
json: { name, app_url: "https://placeholder.invalid", skipGitHubRepo: true },
});
Full code in references/sdk-flow.md. The skill assumes you have:
ELIZAOS_CLOUD_API_KEY in env (Eliza packages this for you)
@elizaos/cloud-sdk available (already a runtime dependency)
- A goal and a name (make the name up if not given; collisions retry once with a 6-char suffix)
Auth + monetization headers
Every cloud-SDK call your deployed app makes on behalf of a user MUST carry:
Authorization: Bearer <user_jwt> — the JWT from the app-auth OAuth redirect
- Optional
x-affiliate-code: <your_affiliate_code> when the owner has configured an affiliate code
This pattern is shared with the eliza-cloud skill; see that skill for the auth flow itself. This skill assumes you've already read it.
Legacy static-hosted variant
Some old/local apps are static frontends served by an existing host instead of
Cloud containers. They are still real Eliza Cloud apps when they use AI
inference, but this is not the production default for Nubilio builds. New
production apps should deploy as their own Eliza Cloud container.
For a static-hosted AI app:
- Build the static UI under the host's app directory.
- Register the app with
/api/v1/apps using the public URL and skipGitHubRepo:true.
- Enable monetization with
PUT /api/v1/apps/<appId>/monetization and the current markup/share schema:
{"monetizationEnabled":true,"inferenceMarkupPercentage":100,"purchaseSharePercentage":10}.
- Write
data/apps/<slug>/cloud.json with only non-secret config: appId, cloudUrl, apiBase, optional affiliateCode, and a model such as openai/gpt-4o-mini. cloudUrl is the browser-facing Cloud frontend/OAuth base that serves /app-auth/authorize; apiBase is the Cloud API base. Use ELIZA_CLOUD_PUBLIC_URL if set, otherwise ELIZA_CLOUD_URL, otherwise use ELIZA_CLOUD_BASE_URL only when that origin also serves the frontend. In local testing, if apiBase is http://localhost:8787/api/v1, cloudUrl must be http://127.0.0.1:3000. Do not point OAuth at an API-only local worker such as :8787, and do not silently mix a localhost API base with production OAuth.
- The browser must use app auth: fetch config, redirect to
/app-auth/authorize, verify state, store the returned user token, and send it as x-user-token.
- The browser must call a same-origin proxy that forwards to Eliza Cloud
/api/v1/apps/<appId>/chat with Authorization: Bearer <user_jwt>. Do not put owner API keys in frontend code and do not fake model responses in local JavaScript.
- Verify the app route, config route, that
${cloudUrl}/app-auth/authorize?... returns the Cloud frontend HTML/redirect rather than JSON resource_not_found, and that chat without a user token returns 401 not_signed_in. If the upstream provider fails, report that as a Cloud provider issue instead of replacing it with a mock assistant.
Read these references in order
references/sdk-flow.md — the 6-step deploy + monetize flow with full code
references/survival-economics.md — why this matters; how earnings flow into hosting
references/failure-modes.md — recovery table for the failures you'll actually hit (name collision, container deploy failure, auth blocker, etc.)
What this skill is NOT
- It is not the app's product code. The skill is the deploy + monetize + survive surface. What the app DOES is up to you given the task.
- It is not a retry loop. Each SDK call is idempotent; if step 5 fails, restart from there.
- It does not configure affiliate codes. Affiliate codes belong to the owner, not the app, and live across all of an owner's apps. The skill inherits whatever is configured.
- It does not assume always-on billing. The org may have set
pay_as_you_go_from_earnings = false, in which case hosting comes purely from credits and earnings stay on the redemption ledger. The skill works either way; the org's owner controls the toggle.
After the app is live — ALWAYS offer a custom domain
The deployed app gets an auto-assigned *.apps.elizacloud.ai subdomain that works immediately. At the end of every successful build, proactively offer the user a custom branded domain (this is part of the standard build flow, not optional polish). Pattern:
-
Use the eliza-cloud-buy-domain skill to call POST /api/v1/domains/search with the app name as the query (limit 3-5 candidates).
-
Filter to .com / .io / .dev / .app if available, sort by price ascending.
-
Present the top 1-2 in your reply, e.g.:
Your app is live at <subdomain> — works right now.
Want me to also grab one of these custom domains for it (one-time charge from your cloud credits)?
• myapp.com — $14.95/yr
• myapp.io — $35.20/yr
Reply yes/no/pick-one.
-
If user accepts, call POST /api/v1/apps/{id}/domains/buy with the chosen domain. The buy is atomic: debit credits → register → DNS → attach.
-
If user declines, do nothing — the auto-subdomain stays as the canonical URL.
Never auto-buy without explicit user yes — every paid step requires confirmation. If the buy succeeds, surface the new URL + note that SSL takes ~1-2 minutes to provision.
After the buy, future "edit dns / detach / list domains" requests are handled by the eliza-cloud-manage-domain skill — point the user there if they ask follow-ups.