---
title: "Create app image"
method: POST
path: "/api/app-images/{handle}"
---

# Create app image

`POST /api/app-images/{handle}`

## Request

- Base URL: `https://reduck.ai`
- URL: `https://reduck.ai/api/app-images/{handle}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Create an installable app in the scope of one handle. It starts private and with no release, so nothing can be installed from it until one is deployed.

## Path parameters

- `handle` string, required: The owner a resource is addressed under: "@username" for a personal scope, or a bare slug for a project.

## Request body

- object
  - `slug` string, required: The image's identifier within its owner's scope. Chosen once and never changed.
  - `name` string, required: A display name. Images are addressed by slug, so this is free to change.
  - `description` string: The one-line summary, carried in every listing unlike `about`. Send "" to clear it.
  - `about` string: Long-form text about the image, not carried in listings. Send "" to clear it.

## Response `201`

Created

- AppImage
  - `id` string, required
  - `slug` string, required: The second half of the address, under `owner.handle`. Chosen at creation and never changes.
  - `name` string, required
  - `description` string, required: The one-line summary, carried in every listing unlike `about`. Empty until one is written.
  - `owner` AppOwner, required
    - `kind` 'user' | 'project', required
    - `handle` string, required: "@username" for a personal scope, the bare slug for a project.
    - `name` string, required
  - `visibility` 'private' | 'public', required
  - `current_release` number, nullable, required: The release every app of this image serves, null until the first deploy.
  - `released_at` string, nullable, required: When the served release shipped, null while there is none.
  - `archived_at` string, nullable, required: Archived images stay installed and running, but take no new installs and are listed nowhere.
  - `install_count` number, required: How many apps run this image, across every scope. What an archive has to answer for.
  - `created_at` string, required
  - `updated_at` string, required
  - `about` string, required: Long-form text about the image, empty until written. Answered exactly as written, so whatever renders it decides whether it is markdown.
  - `manifest` AppImageManifest, required
    - `secrets` AppImageSecretDeclaration[], required: Every `${VAR}` the release's grant references, declared so an install can ask for them.
      - `name` string, required
      - `label` string, required: Human label for the field. Falls back to the name when the author wrote none.
      - `description` string, required: Where to get the value, shown under the field. Empty when the author wrote none.
      - `required` boolean, required: False for a secret the app can work without; the form marks the rest as needed.
      - `page` boolean, required: Whether the page may spend this one, rather than only the app's own server-side tasks.
    - `settings` unknown, required
    - `hooks` AppImageHooks, required
      - `init` string, nullable, required: Runs once in an app's life, at its first page open.
      - `newUser` string, nullable, required: Runs once per person, the first time they open the app.
    - `scripts` string[], required: The Reduck scripts the app may run through the `reduck` door, as `[owner/]host/slug` addresses. A run naming any other script is refused. Empty for a release that declares none, and then the door runs nothing.
  - `api_grant` unknown, required
  - `config_defaults` unknown, required
  - `release_count` number, required

## Other responses

- `400`: Invalid request
- `401`: Not authenticated
- `403`: Forbidden
- `404`: Not found
- `409`: That scope already uses this slug. A slug is the address and never changes, so pick another.

---

[API](https://skmtc.dev/reduck/apis/reduck-api.md) · [All operations](https://skmtc.dev/reduck/apis/reduck-api/llms.txt) · [OpenAPI document](https://skmtc.dev/reduck/apis/reduck-api/revisions/a573b91206d6?raw)
