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, exact app charge requests, x402 payment requests, payout redemptions, 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):
- Implementation contract: use the Cloud SDK registration, same-origin OAuth proxy,
/api/v1/messages forwarding, health check, and container-deploy flow described below. Do not substitute a legacy message route or a client-side owner key.
- SDK reference:
@elizaos/cloud-sdk README — typed methods + helpers + auth.
- Human-readable recipe:
packages/docs/cloud/monetized-apps.mdx — same loop, narrative form, with the schema fields explained.
Skill Pairing
Always pair this skill with eliza-cloud. This
skill owns the new-app build-and-monetize flow; eliza-cloud owns the current
Cloud backend surface, existing-app operations, app charge requests, x402
requests, affiliate earnings, payout redemptions, media/promotion, and
parent-agent Cloud command details. Spawned coding agents should load or
request both skills for Cloud app builds.
The survival-economics loop
An 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 packages/cloud/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 });
// 1. register the app. skipGitHubRepo: true makes this a TEMPLATE app — the
// cloud stamps the first-party template image onto it, so create -> deploy
// resolves to a prebuilt, allowlisted image with NO build step.
const { app, apiKey } = await cloud.createApp({
name,
app_url: "https://placeholder.invalid",
skipGitHubRepo: true,
});
// 2. the app image: PREBUILT + first-party only. Apps deploy an allowlisted
// `ghcr.io/elizaos/*` image (default `ghcr.io/elizaos/example-edad:showcase`,
// override APP_DEFAULT_TEMPLATE_IMAGE). You do NOT build or push your own
// image to an arbitrary registry — build-from-repo is disabled.
// 3. deploy: await cloud.deployApp(app.id); then poll cloud.getAppDeployStatus(app.id).
// GATED: returns 503 { code: "apps_deploy_disabled" } unless APPS_DEPLOY_ENABLED=1
// on the Worker AND the org is allowlisted.
// 4. enable monetization: await cloud.updateMonetization(app.id, { ... })
// 5. patch app_url + allowed_origins to the deployed URL: await cloud.updateApp(app.id, { ... })
// 6. report URLs to the human (the auto-assigned *.apps.eliza.app
// subdomain is the default; if the user wants a custom branded domain
// instead, hand off to the `eliza-cloud-buy-domain` skill)
If this flow is being executed by a spawned coding agent, use the parent-agent
Cloud command bridge for account-bound app creation, deployment, monetization,
charges, x402 requests, domains, media, and advertising. The direct SDK examples
show the parent/app runtime shape; they are not permission to pass raw owner
API keys or wallet keys to child workers.
ViewKind contract for Cloud app views
If the app is delivered as an elizaOS plugin or contributes any Plugin.views
entry, set viewKind explicitly:
release — finished user-facing views; this is the default for production
app views.
preview — unfinished or experimental views hidden until enabled.
developer — dev tooling such as logs, inspectors, debuggers, editors,
diagnostics, deployment panels, or admin consoles.
system — reserved for built-in elizaOS shell views; never use it in a
generated Cloud app plugin.
After launch: charging and payout
Use the eliza-cloud skill and its
references/payments-and-promotion.md details for exact charge flows.
- Use
POST /api/v1/apps/{id}/charges for reusable Stripe/OxaPay requests.
The payer checks out via Stripe/OxaPay; this funds the per-app credit pool
and credits the app-credit earnings ledger — note this is the stranded per-app pool (issue #8253), not the live inference revenue path. The working inference revenue model is the caller's org-credit balance + recordCreatorEarnings (markup added to the org-balance debit), not the per-app pool.
- Use
POST /api/v1/x402/requests for direct wallet-native crypto payments.
Current settlement support includes Base, Ethereum, BSC, and Solana, with the
hosted default at https://x402.eliza.app.
- Include
callback_channel metadata (roomId, agentId) when the agent
should announce payment success/failure in the initiating room.
- Use
/api/v1/redemptions to request creator payouts in elizaOS tokens on
Base, BSC/BNB, Ethereum, or Solana. The payout is fixed to the USD quote at
request time and then admin reviewed/processed. Send asset: "eliza"
explicitly; legacy raw omission defaults to USDC and must not be paired with
an elizaOS-token quote.
- If running through
@elizaos/plugin-elizacloud, browser/app code should use
/api/cloud/billing/* local aliases instead of handling Cloud credentials.
Full code in references/sdk-flow.md. The skill assumes you have:
ELIZAOS_CLOUD_API_KEY in the parent/app runtime env (Eliza packages this
for you) or the parent-agent Cloud command bridge for spawned workers
@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
- App identity via the
x-app-id: <appId> header on POST /api/v1/messages (debits the user's org credit balance and records creator earnings; the affiliate header is honored here, unlike the app-scoped chat route)
- 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 agent-built Cloud apps.
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}.
- Store only non-secret app config next to the frontend:
appId, cloudUrl, apiBase, optional affiliateCode, and a model such as openai/gpt-5-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 and no ELIZA_CLOUD_PUBLIC_URL is configured, 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.eliza.app 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.
1---2name: build-monetized-app3description: 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, app charge requests, x402 payment requests, payout redemptions, 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.4---5
6# Build a monetized app on Eliza Cloud
7
8Use 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, exact app charge requests, x402 payment requests, payout redemptions, and creator-monetization plumbing — you do not need to invent any of these.
9
10Read `references/sdk-flow.md` for the 6-step build flow with a self-contained code example. External references (all public):
11
12- **Implementation contract**: use the Cloud SDK registration, same-origin OAuth proxy, `/api/v1/messages` forwarding, health check, and container-deploy flow described below. Do not substitute a legacy message route or a client-side owner key.
13- **SDK reference**: [`@elizaos/cloud-sdk` README](https://github.com/elizaos/eliza/blob/develop/packages/cloud/sdk/README.md) — typed methods + helpers + auth.
14- **Human-readable recipe**: [`packages/docs/cloud/monetized-apps.mdx`](https://github.com/elizaos/eliza/blob/develop/packages/docs/cloud/monetized-apps.mdx) — same loop, narrative form, with the schema fields explained.
15
16## Skill Pairing
17
18Always pair this skill with [`eliza-cloud`](../eliza-cloud/SKILL.md). This
19skill owns the new-app build-and-monetize flow; `eliza-cloud` owns the current
20Cloud backend surface, existing-app operations, app charge requests, x402
21requests, affiliate earnings, payout redemptions, media/promotion, and
22parent-agent Cloud command details. Spawned coding agents should load or
23request both skills for Cloud app builds.
24
25## The survival-economics loop
26
27An 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 `packages/cloud/api/cron/container-billing/route.ts`).
28
29This is why the skill exists: making money is how the agent stays online.
30
31## Default flow
32
33```ts
34import { ElizaCloudClient } from "@elizaos/cloud-sdk";
35
36const cloud = new ElizaCloudClient({ apiKey: process.env.ELIZAOS_CLOUD_API_KEY });
37
38// 1. register the app. skipGitHubRepo: true makes this a TEMPLATE app — the
39// cloud stamps the first-party template image onto it, so create -> deploy
40// resolves to a prebuilt, allowlisted image with NO build step.
41const { app, apiKey } = await cloud.createApp({
42 name,
43 app_url: "https://placeholder.invalid",
44 skipGitHubRepo: true,
45});
46
47// 2. the app image: PREBUILT + first-party only. Apps deploy an allowlisted
48// `ghcr.io/elizaos/*` image (default `ghcr.io/elizaos/example-edad:showcase`,
49// override APP_DEFAULT_TEMPLATE_IMAGE). You do NOT build or push your own
50// image to an arbitrary registry — build-from-repo is disabled.
51// 3. deploy: await cloud.deployApp(app.id); then poll cloud.getAppDeployStatus(app.id).
52// GATED: returns 503 { code: "apps_deploy_disabled" } unless APPS_DEPLOY_ENABLED=1
53// on the Worker AND the org is allowlisted.
54// 4. enable monetization: await cloud.updateMonetization(app.id, { ... })
55// 5. patch app_url + allowed_origins to the deployed URL: await cloud.updateApp(app.id, { ... })
56// 6. report URLs to the human (the auto-assigned *.apps.eliza.app
57// subdomain is the default; if the user wants a custom branded domain
58// instead, hand off to the `eliza-cloud-buy-domain` skill)
59```
60
61If this flow is being executed by a spawned coding agent, use the `parent-agent`
62Cloud command bridge for account-bound app creation, deployment, monetization,
63charges, x402 requests, domains, media, and advertising. The direct SDK examples
64show the parent/app runtime shape; they are not permission to pass raw owner
65API keys or wallet keys to child workers.
66
67## ViewKind contract for Cloud app views
68
69If the app is delivered as an elizaOS plugin or contributes any `Plugin.views`
70entry, set `viewKind` explicitly:
71
72- `release` — finished user-facing views; this is the default for production
73 app views.
74- `preview` — unfinished or experimental views hidden until enabled.
75- `developer` — dev tooling such as logs, inspectors, debuggers, editors,
76 diagnostics, deployment panels, or admin consoles.
77- `system` — reserved for built-in elizaOS shell views; never use it in a
78 generated Cloud app plugin.
79
80## After launch: charging and payout
81
82Use the [`eliza-cloud`](../eliza-cloud/SKILL.md) skill and its
83`references/payments-and-promotion.md` details for exact charge flows.
84
85- Use `POST /api/v1/apps/{id}/charges` for reusable Stripe/OxaPay requests.
86 The payer checks out via Stripe/OxaPay; this funds the per-app credit pool
87 and credits the app-credit earnings ledger — note this is the stranded per-app pool (issue #8253), not the live inference revenue path. The working inference revenue model is the caller's org-credit balance + `recordCreatorEarnings` (markup added to the org-balance debit), not the per-app pool.
88- Use `POST /api/v1/x402/requests` for direct wallet-native crypto payments.
89 Current settlement support includes Base, Ethereum, BSC, and Solana, with the
90 hosted default at `https://x402.eliza.app`.
91- Include `callback_channel` metadata (`roomId`, `agentId`) when the agent
92 should announce payment success/failure in the initiating room.
93- Use `/api/v1/redemptions` to request creator payouts in elizaOS tokens on
94 Base, BSC/BNB, Ethereum, or Solana. The payout is fixed to the USD quote at
95 request time and then admin reviewed/processed. Send `asset: "eliza"`
96 explicitly; legacy raw omission defaults to USDC and must not be paired with
97 an elizaOS-token quote.
98- If running through `@elizaos/plugin-elizacloud`, browser/app code should use
99 `/api/cloud/billing/*` local aliases instead of handling Cloud credentials.
100
101Full code in `references/sdk-flow.md`. The skill assumes you have:
102
103- `ELIZAOS_CLOUD_API_KEY` in the parent/app runtime env (Eliza packages this
104 for you) or the `parent-agent` Cloud command bridge for spawned workers
105- `@elizaos/cloud-sdk` available (already a runtime dependency)
106- A goal and a name (make the name up if not given; collisions retry once with a 6-char suffix)
107
108## Auth + monetization headers
109
110Every cloud-SDK call your deployed app makes on behalf of a user MUST carry:
111
112- `Authorization: Bearer <user_jwt>` — the JWT from the app-auth OAuth redirect
113- App identity via the `x-app-id: <appId>` header on `POST /api/v1/messages` (debits the user's org credit balance and records creator earnings; the affiliate header is honored here, unlike the app-scoped chat route)
114- Optional `x-affiliate-code: <your_affiliate_code>` when the owner has configured an affiliate code
115
116This pattern is shared with the [`eliza-cloud`](../eliza-cloud/SKILL.md) skill; see that skill for the auth flow itself. This skill assumes you've already read it.
117
118## Legacy static-hosted variant
119
120Some old/local apps are static frontends served by an existing host instead of
121Cloud containers. They are still real Eliza Cloud apps when they use AI
122inference, but this is not the production default for agent-built Cloud apps.
123New production apps should deploy as their own Eliza Cloud container.
124
125For a static-hosted AI app:
126
1271. Build the static UI under the host's app directory.
1282. Register the app with `/api/v1/apps` using the public URL and `skipGitHubRepo:true`.
1293. Enable monetization with `PUT /api/v1/apps/<appId>/monetization` and the current markup/share schema:
130 `{"monetizationEnabled":true,"inferenceMarkupPercentage":100,"purchaseSharePercentage":10}`.
1314. Store only non-secret app config next to the frontend: `appId`, `cloudUrl`, `apiBase`, optional `affiliateCode`, and a model such as `openai/gpt-5-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` and no `ELIZA_CLOUD_PUBLIC_URL` is configured, `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.
1325. 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`.
1336. 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.
1347. 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.
135
136## Read these references in order
137
1381. `references/sdk-flow.md` — the 6-step deploy + monetize flow with full code
1392. `references/survival-economics.md` — why this matters; how earnings flow into hosting
1403. `references/failure-modes.md` — recovery table for the failures you'll actually hit (name collision, container deploy failure, auth blocker, etc.)
141
142## What this skill is NOT
143
144- **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.
145- **It is not a retry loop.** Each SDK call is idempotent; if step 5 fails, restart from there.
146- **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.
147- **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.
148
149## After the app is live — ALWAYS offer a custom domain
150
151The deployed app gets an auto-assigned `*.apps.eliza.app` 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:
152
1531. 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).
1542. Filter to `.com` / `.io` / `.dev` / `.app` if available, sort by price ascending.
1553. Present the top 1-2 in your reply, e.g.:
156
157 > Your app is live at `<subdomain>` — works right now.
158 > Want me to also grab one of these custom domains for it (one-time charge from your cloud credits)?
159 > • `myapp.com` — $14.95/yr
160 > • `myapp.io` — $35.20/yr
161 > Reply yes/no/pick-one.
162
1634. If user accepts, call `POST /api/v1/apps/{id}/domains/buy` with the chosen domain. The buy is atomic: debit credits → register → DNS → attach.
1645. If user declines, do nothing — the auto-subdomain stays as the canonical URL.
165
166**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.
167
168After 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.