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

# Marketplace

> Publish apps so other spaces can discover and install them.

# Marketplace

Publishing an app to the marketplace makes it available for other Kazzle spaces to discover and install.

## What publishing does

Publishing makes the app installable by other spaces. People see the app's
name, subtitle, icon, publisher, and visibility, then install it into their
own space. Publish requires a `subtitle` in `kazzle.config.ts` — a one-line
tagline under the app name.

The published version uses the latest commit on `main`. There is no separate
release branch for published apps.

The app definition explicitly chooses whether clicking an installed app opens a
component, opens an embedded or external URL, or has no launch surface. Apps can
also require Kazzle identity before opening or receive lifecycle webhooks.

See [Publish your app](/apps/build-and-publish) for how to publish an app.

## Installs

When someone installs a published app, Kazzle creates an installation record inside their space. The installing space owns the installation and any data associated with it.

## User identity

When a logged-in Kazzle user opens an installed app, Kazzle provides the app with information about the current user.

Kazzle attaches a short-lived JWT as a bearer token. The app can verify the token against Kazzle's public JWKS to read the user, space, and install.

The token contains these claims:

| Claim     | Meaning                          |
| --------- | -------------------------------- |
| `aud`     | `kazzle:app`                     |
| `iss`     | `https://api.kazzle.app`         |
| `sub`     | Kazzle user ID                   |
| `user`    | `{ id, email }` của người dùng   |
| `space`   | ID của space mà app được cài đặt |
| `install` | ID của installation cụ thể này   |

Example verification:

```ts theme={"theme":"material-theme-darker"}
import { jwtVerify, createRemoteJWKSet } from 'jose';

const JWKS = createRemoteJWKSet(new URL('https://api.kazzle.app/auth/.well-known/jwks.json'));

async function getUserFromToken(token: string) {
  const { payload } = await jwtVerify(token, JWKS, {
    audience: 'kazzle:app',
    issuer: 'https://api.kazzle.app',
  });
  return payload;
}
```

The app definition controls launch behavior for published apps:

* `launch`: selects `none`, a named app component, or a URL with an explicit embedded or external target.
* `kazzleAuth`: `required` means only logged-in Kazzle users can open the app; `optional` allows the app to be opened without a Kazzle identity.

## Webhooks

If the app definition includes a `webhookUrl`, Kazzle sends HTTP POST requests to it when the app is installed or uninstalled.

`app.installed` includes the install key the publisher's backend can use to authenticate to the per-install API:

```json theme={"theme":"material-theme-darker"}
{
  "event": "app.installed",
  "installId": "...",
  "appId": "...",
  "spaceId": "...",
  "apiUrl": "https://api.kazzle.app",
  "installKey": "kzl_inst_...",
  "user": { "id": "...", "email": "..." }
}
```

`app.uninstalled` contains the event, install ID, app ID, space ID, and API URL. The publisher should stop using the install key after receiving this event.

## Per-install API

Each installation can call a scoped API on `https://api.kazzle.app`. Calls are authenticated with either the install key (from the publisher's backend) or the user identity token (from the hosted UI). All operations are automatically scoped to that install.

Available endpoints:

Full request and response schemas are published in the Kazzle OpenAPI spec at
`https://api.kazzle.app/openapi.json` under these paths.

| Method | Path                  | Description                               |
| ------ | --------------------- | ----------------------------------------- |
| GET    | `/apps/secrets`       | List secret names stored for the install  |
| GET    | `/apps/secrets/:name` | Read a secret value                       |
| PUT    | `/apps/secrets/:name` | Store a secret value                      |
| DELETE | `/apps/secrets/:name` | Delete a secret                           |
| GET    | `/apps/metadata`      | Read non-secret metadata for the install  |
| PUT    | `/apps/metadata`      | Merge updates into the install's metadata |

Secrets written through this API are encrypted at rest and isolated to the specific installation. They are separate from secrets stored in a space's vault.

## Next steps

* [Publish your app](/apps/build-and-publish) — how to publish an app and what happens after.
