Skip to navigation

Creating a product

A Product groups your Flows and Agents as Capabilities. It exposes those Capabilities through 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.

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.

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.
  • 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
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 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. 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 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.

Apply an FPO with the following code:

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

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
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".

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
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.

You can create and iterate on Flows and Agents in the Product editor. To create a resource separately, see Creating and editing Flows or 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?.

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.

To test a Capability interactively, start with a Chat Widget Surface. Then add an API Surface or 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.

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: