> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Creating a product

A [Product](/user-guide/products-surfaces/what-are-products) groups your [Flows](/user-guide/flows/what-are-flows) and [Agents](/user-guide/agents/what-are-agents) as Capabilities. It exposes those Capabilities through [Surfaces](/user-guide/products-surfaces/what-are-surfaces), such as chat widgets, REST APIs, Model Context Protocol (MCP) servers, and Agent-to-Agent (A2A) endpoints.

## Before you begin

Create a Flow or Agent, or plan to add one from the Product editor. For a guided example, follow [Quickstart: Build a Social Media Post Generator as a REST API](/user-guide/getting-started/quickstart-social-media-post-generator).

## Create a Product with a Surface

Start with a Surface when you know how people will reach the Product. To create a Product with a Surface in the dashboard, follow these steps:

1. In the sidebar, click **Products**.
2. Click **New product**.
3. Choose **Chat Widget**, **MCP Server**, **REST API**, or **A2A Agent**.
4. In the **Name** field, replace the default name with a descriptive name, such as `Customer Support Assistant`.
5. Select **New Agent**, **Use Existing**, or **Skip for now**.
6. If you selected **Use Existing**, click **Agents** or **Flows**, then select the resource to add.
7. Click **Create** followed by the Surface name, such as **Create Chat Widget**. The Product editor opens with the setup panel of the new Surface.

Use a name that describes what the Product does. The Product name is the default title for generated API documentation and MCP manifests.

The **Use Existing** list shows up to 100 Agents and 100 Flows. The **Add Capability** dialog in the Product editor shows up to 50 of each. If the resource you want is not in the list, select **Skip for now**. After the Product is created, add the resource with the API: send `POST /v1/products/YOUR_PRODUCT_ID/capabilities` with a `capabilityName` and the resource's `agentId` or `flowId`. For an example request, see [Adding capabilities to a product](/user-guide/products-surfaces/adding-capabilities-to-a-product).

### What the dashboard creates

The dashboard creates these resources with the Product:

* **A Surface** of the type you chose, in **Draft** status. Most Surface types reject requests while in Draft. Complete its setup, then set it to **Active**. For more information, see [Product versioning and status](/user-guide/products-surfaces/product-versioning-and-status).
* **An Agent**, if you selected **New Agent**. The Agent is named after the Product, such as `Customer Support Assistant Agent`. It uses the platform default model and a generic "You are a helpful assistant" system prompt.
* **A Capability** for the new or existing resource, connected to the Surface.

A Chat Widget always gets an Agent. If you select **Skip for now** for a Chat Widget, the dashboard still creates an Agent with the same default model and system prompt, and connects it to the Surface.

Before you activate the Surface, open the new Agent and set its system prompt and model for your use case.

## Create an empty Product

Start with an empty Product when you want to add Capabilities and Surfaces later. To create an empty Product, follow these steps:

1. In the sidebar, click **Products**.
2. Click **New product**.
3. Click **Start with an empty product**.
4. In the **Name** field, enter a descriptive name.
5. Click **Create Product**. The Product editor opens.

To skip the name step, choose **Blank product** from the product switcher, the **+ New** menu, the command palette, or the **Blank product** card on the Dashboard. The card appears when you have fewer than three Products. Runtype creates a Product named **Untitled product** and opens it on the canvas, where you can rename it.

## Start from a template

Use a template to deploy a working Product, then edit it. To open the template gallery, do one of these:

* On the **Products** page, click **Templates**.
* In an empty **Products**, **Flows**, or **Agents** list, click **Start from a template**. The **Flows** list opens the gallery filtered to **Flow**, and the **Agents** list opens it filtered to **Agent**.

The gallery groups its cards into two sections:

* **Templates**: Runtype Product templates. Each card carries a badge for every Capability it creates, such as **Agent** or **Flow**.
* **Examples**: published Runtype examples. Example cards carry no Capability badges.

To narrow the gallery, enter a term in **Search templates**, which matches card names and descriptions. To narrow it by Capability, click one of the Capability buttons beside the search field. Besides **All**, only Capability types that at least one template creates get a filter button. The Capability filter applies to the **Templates** section, so the **Examples** section is hidden while a filter other than **All** is active.

Click a template card to open its setup page. Enter a **Product Name**, update the Flow and Agent settings that the template prefills, then click the deploy button, which is labeled **Deploy** followed by the template name. Click an example card to open a preview with an architecture diagram, then create the Product from the same page.

## Generate a Product with AI

In a non-production environment, use **Generate with AI** to describe a Product and review its proposed setup before creation.

To generate a Product with AI, follow these steps:

1. On **Products**, click **Generate with AI**.
2. Describe the Product that you want to build.
3. Answer the interview questions.
4. Review the Product brief and architecture diagram.
5. Correct missing details, then confirm the proposed architecture.
6. Approve the build.
7. Review the created Product in the Product editor, then customize its Capabilities and Surfaces.

Nothing is created until you approve the build. You can revise the proposal during the interview before you approve it.

## Create a Product with the API

To create a Product from code, send a `POST` request to `/v1/products`. Only `name` is required. The following request creates an empty Product:

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/v1/products \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Customer Support Assistant",
    "description": "Answers questions about orders and returns"
  }'
```

Replace `YOUR_API_KEY` with a Runtype API key. The key needs the `PRODUCTS:CREATE`, `PRODUCTS:WRITE`, or `PRODUCTS:*` permission.

The response includes the Product ID. Add Capabilities and Surfaces from the Product editor or with the other product endpoints. For the request fields and endpoints, see [Create product](/api-reference/runtype-api/products/create-product) in the API reference.

To keep a Product definition in source control, use `defineProduct` with `Runtype.products.ensure()` from the `@runtypelabs/sdk` package. `ensure` creates the Product or updates it to match the definition. It manages only the Product's `name`, `description`, `icon`, and `spec`, not its Capabilities or Surfaces. To manage one Surface as code, use `Runtype.surfaces.ensure()`. For more information, see [Manage surfaces as code](/user-guide/products-surfaces/manage-surfaces-as-code). To manage the Product with its Capabilities and Surfaces in one call, use `Runtype.products.ensureFpo()`, described in the following section.

AI assistants connected to the [Runtype MCP server](/developer-guides/integrations/runtype-mcp-server) can call the `create_product` tool, or `create_product_from_example` to deploy an example.

## Manage a whole Product as code

`Runtype.products.ensureFpo()` applies a full product object (FPO) from your repository: the Product and the Flows, Agents, Capabilities, Tools, Surfaces, records, schedules, eval suites, and skills that it declares. It matches the Product by `product.name` within your organization or personal account, then creates or updates each nested entity to match the FPO. For the FPO format, see [FPO templates](/developer-guides/guides/fpo-templates).

Apply an FPO with the following code:

**`TypeScript SDK`**

```typescript title="TypeScript SDK"
import { Runtype, defineFpo } from '@runtypelabs/sdk'
import supportProduct from './support-product.fpo.json'

Runtype.configure({ apiKey: process.env.RUNTYPE_API_KEY })

const result = await Runtype.products.ensureFpo(defineFpo(supportProduct))
if (result.hasFailures) {
  console.error(result.entities.filter((entity) => entity.result === 'failed'))
  process.exit(1)
}
```

The sample exits with a non-zero code when any entity fails, so a CI job that runs it fails instead of passing with part of the Product applied.

`defineFpo` checks only that the FPO has a non-empty `product.name`. The API validates the rest of the FPO and returns status code `400` if it's invalid.

The response includes the following fields:

* `result`: `unchanged` when nothing changed, `converged` when at least one entity was created, updated, or pruned, and `plan` for a dry run.
* `productId` and `contentHash`: the Product ID and the hash of the whole FPO.
* `entities`: one row per nested entity, with its `kind`, `name`, `result`, and `id`. The `result` value is `created`, `updated`, `unchanged`, `failed`, `skipped`, or `pruned`. A `failed` row also has an `error`.
* `hasFailures`: `true` when any entity failed.

`ensureFpo` isn't atomic. When one entity fails, the entities that succeeded keep their changes. Fix the cause in the `error` field and run `ensureFpo` again. Entities that already match return `unchanged`.

Your API key needs the `PRODUCTS:WRITE` or `PRODUCTS:*` permission, or `PRODUCTS:CREATE` and `PRODUCTS:UPDATE`. Each nested Flow, Agent, schedule, record, eval suite, and skill also needs the write permission for its kind, such as `FLOWS:WRITE`. Without it, that entity reports `failed`. If the FPO declares secrets, the key also needs `SECRETS:WRITE`.

`ensureFpo` accepts these options:

* `dryRun: true`: returns a per-entity plan and writes nothing.
* `onConflict: 'overwrite'`: converges nested entities over edits made outside code, such as dashboard edits.
* `prune: true`: removes Capabilities and Surfaces that the FPO no longer declares. For details, see [Remove entities with prune](#remove-entities-with-prune).

### Remove entities with prune

By default, `ensureFpo` doesn't remove Capabilities or Surfaces from the Product. When you remove a Capability or Surface from the FPO, the saved one stays in the Product. To remove it, pass `prune: true`. Run it as a dry run first, which reports each removal as a `pruned` row and deletes nothing:

**`TypeScript SDK`**

```typescript title="TypeScript SDK"
const plan = await Runtype.products.ensureFpo(supportProduct, { dryRun: true, prune: true })
console.log(plan.entities.filter((entity) => entity.result === 'pruned'))
```

After `ensureFpo` applies the FPO, `prune` deletes the following from the Product:

* Every Capability whose name isn't in the FPO's `capabilities`.
* Every Surface whose name isn't in the FPO's `surfaces`.
* On each Surface that the FPO keeps, every connection to a Capability that the Surface's `routes` no longer list. The `entities` list doesn't report these removals.

The dry-run plan doesn't show these connection removals either. Before you apply `prune`, compare each kept Surface's `routes` in the FPO with the Capabilities that the Surface exposes in the Product editor. Any Capability that the Surface exposes but its `routes` don't list loses its connection.

`prune` never deletes Flows, Agents, Tools, or records, because they belong to your account and other Products can use them. It also keeps any Capability or Surface that the FPO declares with `createPolicy: "skip"`.

> **Warning**
>
> A pruned Capability or Surface can't be restored. Check the dry-run plan before you apply `prune`.

### Pull a Product into an FPO

To start from a Product that you built in the dashboard, pull it as an FPO:

**`TypeScript SDK`**

```typescript title="TypeScript SDK"
const { productId, fpo, contentHash, warnings } = await Runtype.products.pullFpo(
  'Customer Support Assistant'
)
```

`pullFpo` rebuilds the Product, the Flows and Agents behind its Capabilities, and its Surfaces. It also includes the Product's secret declarations, and the schedules, eval suites, and skills that belong to those Flows and Agents. It doesn't include records, and it returns an empty `tools` list, because the pulled Flows and Agents refer to Tools by name. The `warnings` array lists what the pull left out. Review the FPO, add what you need, and run `ensureFpo` with `dryRun: true` before you apply it.

Your API key needs `PRODUCTS:READ` or `PRODUCTS:*`. It also needs the read permission for each kind of entity that the Product has: `FLOWS:READ`, `AGENTS:READ`, `SCHEDULES:READ`, `EVALS:READ`, and `SKILLS:READ`. Without one of these, `pullFpo` fails with status code `403`. If no Product has that name, `pullFpo` fails with status code `404`.

## Add Capabilities

After you create a Product, click **Add Capability** in **List view** or **Visual view**.

Choose one of these options:

* **New Agent**: Create an Agent to power the Product.
* **New Flow**: Create a Flow to power the Product.
* **External A2A**: Connect an external A2A-compatible Agent built with LangChain, CrewAI, Vercel AI SDK, or another framework.
* **Use Existing**: Select an existing Agent or Flow.

Give each Capability a unique name. Add a description when you want to explain its purpose. For the full workflow, see [Adding capabilities to a Product](/user-guide/products-surfaces/adding-capabilities-to-a-product).

You can create and iterate on Flows and Agents in the Product editor. To create a resource separately, see [Creating and editing Flows](/user-guide/flows/creating-and-editing-flows) or [Creating and configuring Agents](/user-guide/agents/creating-and-configuring-agents).

## Add Surfaces

To expose Capabilities, go to the **Product surfaces** section and click **Add Surface**. The **Add Surface** dialog lists web Surfaces, such as **Chat Widget** and **REST API**, and messaging channels, such as **Slack Channel** and **Email Channel**. To compare every Surface type, see [What are Surfaces?](/user-guide/products-surfaces/what-are-surfaces).

Add multiple Surfaces to a Product, then choose which Capabilities each Surface exposes.

To keep a Surface's settings in your repository, see [Manage surfaces as code](/user-guide/products-surfaces/manage-surfaces-as-code).

To test a Capability interactively, start with a [Chat Widget Surface](/user-guide/products-surfaces/setting-up-a-chat-surface). Then add an [API Surface](/user-guide/products-surfaces/setting-up-an-api-surface) or [MCP Surface](/user-guide/products-surfaces/setting-up-an-mcp-surface) when you are ready to integrate.

## Configure Product details

To update a Product's name or description, open the Product editor and select the Product node in **Visual view**. Edit **Name** or **Description**, then click **Save**.

To switch between the architecture graph and the list layout of a Product, see [Product views](/user-guide/products-surfaces/product-views).

## Troubleshooting

These problems can occur when you create a Product:

* **"Product created but failed to add surface"** or **"Product created but failed to add capability"**: the Product exists, but one part was not added. Don't create the Product again, because that makes a duplicate. Open the Product and click **Add Surface** or **Add Capability** to add the missing part. If you selected **New Agent**, check the **Agents** list first. The Agent might exist already, so add it with **Use Existing**.
* **`403` with `Insufficient permissions` from the API**: the API key lacks a product permission. Use a key with the `PRODUCTS:CREATE`, `PRODUCTS:WRITE`, or `PRODUCTS:*` permission.
* **A Surface rejects requests**: the Surface might still be in **Draft** status. Set it to **Active** after you complete its setup.

## Next steps

Continue with one of these guides:

* [Add capabilities to a Product](/user-guide/products-surfaces/adding-capabilities-to-a-product): connect Flows and Agents to your Product.
* [Manage surfaces as code](/user-guide/products-surfaces/manage-surfaces-as-code): apply Surface definitions from your repository.
* [Set up a Chat Widget Surface](/user-guide/products-surfaces/setting-up-a-chat-surface): test a Capability in a chat interface.
* [Set up an API Surface](/user-guide/products-surfaces/setting-up-an-api-surface): expose a Capability through HTTP.
* [Set up an MCP Surface](/user-guide/products-surfaces/setting-up-an-mcp-surface): connect AI assistants to your Capabilities.
* [Product versioning and status](/user-guide/products-surfaces/product-versioning-and-status): activate a Surface so it accepts requests.
* [Product views](/user-guide/products-surfaces/product-views): work with the architecture graph and the list layout.