> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uos.agency/llms.txt
> Use this file to discover all available pages before exploring further.

# Publish an app

> Add your Mini App to the uOS App Store step by step

export const AppStoreSuccessPreview = () => <div className="uos-doc-preview uos-doc-preview--store" aria-label="App Store install success preview">
    <div className="uos-store-panel uos-store-panel--center">
      <div className="uos-store-success">
        <div className="uos-store-success__icon" aria-hidden="true">✓</div>
        <h4 className="uos-store-success__title">Installation Complete</h4>
        <p className="uos-store-success__body">Mpay is on your desktop. Open it anytime from the dock or desktop icon.</p>
        <span className="uos-store-install-btn">Open</span>
      </div>
    </div>
  </div>;

export const AppStoreDetailsPreview = () => <div className="uos-doc-preview uos-doc-preview--store" aria-label="App Store details preview">
    <div className="uos-store-panel">
      <div className="uos-store-head uos-store-head--details">
        <span className="uos-store-back" aria-hidden="true">‹</span>
        <span className="uos-store-head__title">Mpay</span>
      </div>
      <div className="uos-store-body uos-store-body--stack">
        <div className="uos-store-detail-hero">
          <img src="/assets/mpay-icon.svg" alt="" className="uos-store-card__icon uos-store-card__icon--xl" />
          <div className="uos-store-card__meta">
            <div className="uos-store-card__title-row">
              <span className="uos-store-card__name">Mpay</span>
              <span className="uos-store-pill">Payments</span>
            </div>
            <p className="uos-store-card__desc">
              Send tokens without paying gas. Gasless stablecoin and ERC-20 transfers powered by x402 and EIP-2612 permits.
            </p>
            <div className="uos-store-meta-stack">
              <span className="uos-store-meta">pay.mrdn.finance</span>
              <span className="uos-store-meta">Unverified</span>
            </div>
          </div>
        </div>

        <div className="uos-store-perms">
          <div className="uos-store-perms__head">Permissions</div>
          <div className="uos-store-perm">
            <code>wallet:request</code>
            <p>Read your connected wallet address and chain</p>
          </div>
          <div className="uos-store-perm">
            <code>wallet:sign</code>
            <p>Request transactions and signatures (each one requires your approval)</p>
          </div>
        </div>

        <span className="uos-store-install-btn">Install</span>
      </div>
    </div>
  </div>;

export const AppStoreListPreview = () => <div className="uos-doc-preview uos-doc-preview--store" aria-label="App Store list preview">
    <div className="uos-store-panel">
      <div className="uos-store-head">
        <div className="uos-store-search">
          <span className="uos-store-search__icon" aria-hidden="true" />
          <span className="uos-store-search__placeholder">Search apps...</span>
        </div>
      </div>
      <div className="uos-store-body">
        <h4 className="uos-store-section-title">Featured Apps</h4>
        <div className="uos-store-grid">
          <div className="uos-store-card">
            <img src="/assets/ugame-icon.png" alt="" className="uos-store-card__icon" />
            <div className="uos-store-card__meta">
              <div className="uos-store-card__title-row">
                <span className="uos-store-card__name">uGAME</span>
                <span className="uos-store-pill">Games</span>
              </div>
              <div className="uos-store-card__desc">
                The ultimate retro gaming platform for your uOS desktop. Enjoy classic games with modern...
              </div>
              <div className="uos-store-card__footer">
                <span className="uos-store-card__cta">Pre-installed</span>
              </div>
            </div>
          </div>
          <div className="uos-store-card">
            <img src="/assets/mpay-icon.svg" alt="" className="uos-store-card__icon" />
            <div className="uos-store-card__meta">
              <div className="uos-store-card__title-row">
                <span className="uos-store-card__name">Mpay</span>
                <span className="uos-store-pill">Payments</span>
              </div>
              <div className="uos-store-card__desc">
                Send tokens without paying gas. Gasless stablecoin and ERC-20 transfers powered by x402...
              </div>
              <div className="uos-store-card__footer">
                <span className="uos-store-card__cta">Get</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>;

export const DevPortalPublishPreview = () => <div className="uos-doc-preview uos-doc-preview--dev" aria-label="Dev Portal publish preview">
    <div className="uos-dev-panel">
      <div className="uos-dev-titleblock">
        <img src="/assets/dev-portal-icon.png" alt="" className="uos-dev-titleblock__icon" />
        <h4 className="uos-dev-titleblock__title" aria-label="Dev Portal">
          <span className="uos-dev-titleblock__muted">Dev </span>
          <span className="uos-dev-titleblock__accent">Portal</span>
        </h4>
      </div>

      <div className="uos-dev-tabs">
        <span className="uos-dev-tab uos-dev-tab--active">Publish</span>
        <span className="uos-dev-tab">Analytics</span>
        <span className="uos-dev-tab">Settings</span>
      </div>

      <section className="uos-dev-card">
        <div className="uos-dev-card__head">
          <span className="uos-dev-card__title">Your apps</span>
          <span className="uos-dev-card__action">Refresh</span>
        </div>
        <div className="uos-dev-app-row">
          <img src="/assets/mpay-icon.svg" alt="" className="uos-dev-app-row__icon" />
          <div className="uos-dev-app-row__meta">
            <div className="uos-dev-app-row__name-row">
              <span className="uos-dev-app-row__name">Mpay</span>
              <span className="uos-dev-badge uos-dev-badge--live">Live</span>
            </div>
            <span className="uos-dev-app-row__domain">pay.mrdn.finance</span>
          </div>
          <div className="uos-dev-app-row__actions">
            <span className="uos-dev-chip">Update</span>
            <span className="uos-dev-chip uos-dev-chip--danger">Unpublish</span>
          </div>
        </div>
      </section>

      <section className="uos-dev-card uos-dev-card--pad">
        <p className="uos-dev-eyebrow">Publish</p>
        <p className="uos-dev-card__title">Add a Mini App</p>
        <p className="uos-dev-body">
          Host <code>/.well-known/uos-app.json</code> on your domain, then enter the domain below.
        </p>
        <div className="uos-dev-wallet">
          <span className="uos-dev-wallet__label">Publisher wallet</span>
          <span className="uos-dev-wallet__addr">0xA1b2…9f3E</span>
        </div>
        <div className="uos-dev-publish-row">
          <div className="uos-dev-input">
            <span className="uos-dev-input__icon" aria-hidden="true" />
            <span className="uos-dev-input__placeholder">pay.example.com</span>
          </div>
          <span className="uos-dev-publish-btn">Publish</span>
        </div>
      </section>
    </div>
  </div>;

Get your app into the uOS App Store in five steps. You host the app. uOS fetches your manifest and lists it for install.

## Step 1: Host your app

Deploy a public website on **your** domain (not the uOS origin). Mini Apps run in a sandboxed iframe on your origin; that domain is the trust boundary.

Your app URL becomes `entry.url` in the manifest. It must stay on the **same host** as the manifest. Localhost and private hosts are rejected.

## Step 2: Add the manifest

Serve JSON at `https://your-domain/.well-known/uos-app.json` with **no redirects**:

```json theme={null}
{
  "name": "My App",
  "version": "1.0.0",
  "description": "What your app does in one or two sentences.",
  "icon": "https://your-domain.com/icon.png",
  "category": "Apps",
  "entry": {
    "type": "iframe",
    "url": "https://your-domain.com/"
  },
  "permissions": ["wallet:request"],
  "author": {
    "wallet": "0xYourWalletAddress"
  }
}
```

**Required for a valid manifest:** `name`, `entry.type` (`"iframe"`), and `entry.url` (public `http:`/`https:`, same host as the manifest).

**Required for Dev Portal publish:** `author.wallet` must equal the wallet you connect and sign with.

See the full [manifest reference](/developers/manifest) for icons, screenshots, tags, `price`, and the optional verified-author signature.

<Note>
  uOS fetches the manifest with a 5 second timeout, a 512 KB size cap, and `redirect: 'error'`. The well-known URL must respond directly with JSON.
</Note>

## Step 3: Open Dev Portal

In uOS, open **Dev Portal** from the dock and connect your wallet from the menu bar.

<DevPortalPublishPreview />

<div className="uos-doc-preview-caption">Dev Portal: Publish tab with your apps list and domain field</div>

## Step 4: Publish

1. Confirm `author.wallet` in your manifest matches the connected wallet.
2. Enter your domain (for example `pay.example.com`).
3. Click **Publish**.
4. Sign the free message in your wallet (no gas; this is a message signature, not a transaction).

Self-serve publish goes **live in the App Store immediately** (registered as `approved`). Re-publishing the same domain refreshes the existing catalog entry in place (one catalog entry per domain).

| Action in Dev Portal | What it does                                                                               |
| -------------------- | ------------------------------------------------------------------------------------------ |
| **Publish**          | Signs `action: publish`, fetches the manifest, registers or refreshes the app              |
| **Update**           | Same as publish for an app you already own (re-fetch + refresh)                            |
| **Unpublish**        | Soft-removes the app from the public catalog (`deleted_at`); installs keep the same app id |
| **Republish**        | Shown when unpublished; runs publish again to bring the listing back                       |

The signed publish message is:

```
uOS App Publish v1
action: publish
domain: <domain, lowercase>
wallet: <wallet, lowercase>
issued-at: <ISO-8601 timestamp>
```

Unpublish uses the same template with `action: unpublish`.

`issued-at` must be within **10 minutes** of server time in either direction (stale and far-future timestamps are rejected). Publish/unpublish is rate limited to **10 requests per 60 seconds** per wallet and per client IP.

## Step 5: Users install from the App Store

Anyone can open the **App Store**, find your app, and install it. That adds a desktop icon. Installed apps sync to the user's account when they are **signed in** (wallet SIWE session), not merely connected.

<AppStoreListPreview />

<div className="uos-doc-preview-caption">App Store: featured apps with Get / Installed / Pre-installed</div>

Selecting an app opens details: description, domain, author verification, permissions, and screenshots.

<AppStoreDetailsPreview />

<div className="uos-doc-preview-caption">App details: permissions review before Install</div>

Tapping **Install** adds the app to the desktop and pins the permission set the user just reviewed. Later permission additions require re-consent on open.

<AppStoreSuccessPreview />

<div className="uos-doc-preview-caption">Install complete: the app is ready to open from the desktop</div>

## Checklist

* [ ] App is hosted on your own domain (not the uOS origin)
* [ ] `/.well-known/uos-app.json` is reachable with no redirects
* [ ] `entry.url` is on the same host as the manifest
* [ ] `author.wallet` matches your Dev Portal wallet
* [ ] Only the [permissions](/developers/manifest#permissions) you need are listed
* [ ] Optional: [domain-association signature](/developers/manifest#verified-author) for the Verified badge
* [ ] Optional: load the [App SDK](/developers/sdk) and call `uOS.ready()`

## After you're live

* **Update:** change the manifest on your domain, then hit **Update** in Dev Portal (bump `version` if you want the store to show a new version string)
* **[Analytics](/developers/analytics):** one-time 10 USDC unlock for installs, opens, retention, and related metrics
* **Settings:** set a payout wallet for future app-purchase revenue (defaults to `author.wallet`; changing it requires a fresh signature and takes effect after **72 hours**; resetting to the publisher wallet is immediate)

<Tip>
  For wallet, filesystem, and window APIs inside your iframe, see the [App SDK](/developers/sdk).
</Tip>
