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

# Importing products

> Preview and deploy products from Agent-to-Agent (A2A) agent cards, Full Product Objects, and FPO templates

Preview a product from a JSON document, then create it in your account. The [dashboard import page](https://use.runtype.com/now) uses the same endpoints that this guide describes.

## Before you begin

* To create a product, you need a Runtype API key. For more information, see [Authentication](/developer-guides/getting-started/authentication).
* The preview endpoints don't require authentication.

## Supported sources

The import APIs accept these JSON sources:

* Agent-to-Agent (A2A) agent cards.
* Raw Full Product Object (FPO) JSON.
* FPO template JSON.

The import APIs reject these sources:

* GitHub repository homepages.
* `README` and Markdown URLs.
* Raw JSON passed through query parameters.
* Generic website or repository crawling.

Use GitHub URLs only for specific JSON files. The import service converts GitHub `blob` URLs to raw file URLs before it fetches them. It accepts raw GitHub file URLs as they are. For a gist, use a raw gist file URL that points to one JSON file.

A source URL must use `https` and respond with a `Content-Type` of `application/json` or `text/plain`, and the document must be 256 KB or smaller. The same size limit applies to pasted JSON.

### Supported versions

The following table lists the `version` values that each source type accepts:

| Source type  | Accepted `version` values                                                    | Notes                                                                                        |
| ------------ | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Raw FPO      | `1.0`, `1.1`, `2.0`                                                          | `2.0` is the current version. An inline agent keeps its runtime fields under `agent.config`. |
| FPO template | Top level: `1.0`, `1.1`. Nested `productObject.version`: `1.0`, `1.1`, `2.0` | The nested product object follows the raw FPO rules.                                         |

At `1.0` and `1.1`, an inline agent keeps its runtime fields, such as `model`, directly on the agent object.

## Import flow

To import a product, follow these steps:

1. Preview the source with `POST /v1/quick-start/imports/preview`.
2. Optional: Reload the preview with `GET /v1/quick-start/imports/:token`.
3. Create the product with `POST /v1/quick-start/create`.
4. Finish setup in the dashboard.

## Step 1: Preview an import source

Choose a hosted URL or paste the JSON document into the request body.

### Preview a hosted JSON document

To preview a public JSON file, send a URL source. The following TypeScript example sends the request:

**`TypeScript`**

```typescript title="TypeScript"
const previewResponse = await fetch('https://api.runtype.com/v1/quick-start/imports/preview', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: {
      kind: 'url',
      url: 'https://example.com/YOUR_PRODUCT.json',
    },
  }),
})

const preview = await previewResponse.json()
console.log(preview.importToken)
console.log(preview.sourceType) // "fpo"
console.log(preview.preview.productName)
```

Replace `https://example.com/YOUR_PRODUCT.json` with the public URL of your FPO, FPO template, or agent card.

The following cURL command sends the same request:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/quick-start/imports/preview \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "kind": "url",
      "url": "https://example.com/YOUR_PRODUCT.json"
    }
  }'
```

### Preview pasted JSON

To preview a document that you already have in memory, send a JSON source with its contents in `content`. The following TypeScript example reads a template file from your app and submits it:

**`TypeScript`**

```typescript title="TypeScript"
const templateDocument = await fetch('/YOUR_TEMPLATE_FILENAME.json').then((response) =>
  response.text()
)

const previewResponse = await fetch('https://api.runtype.com/v1/quick-start/imports/preview', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: {
      kind: 'json',
      label: 'Customer Support Template',
      content: templateDocument,
    },
  }),
})

const preview = await previewResponse.json()
console.log(preview.sourceType) // "fpo-template"
console.log(preview.template?.variables)
```

Replace `YOUR_TEMPLATE_FILENAME` with the filename that your app serves.

The following cURL command sends a template as a JSON string in `content`:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/quick-start/imports/preview \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
{
  "source": {
    "kind": "json",
    "label": "Customer Support Template",
    "content": "{\"version\":\"1.1\",\"productObject\":{\"version\":\"2.0\",\"product\":{\"name\":\"{{productName}}\",\"description\":\"Support automation for {{companyName}}\"},\"capabilities\":[{\"id\":\"cap_support\",\"name\":\"Support Agent\",\"description\":\"Handle incoming support requests.\",\"agent\":{\"name\":\"{{productName}} Agent\",\"description\":\"Handle support requests for {{companyName}}.\",\"config\":{\"model\":\"claude-sonnet-5\"}}}],\"tools\":[],\"surfaces\":[{\"id\":\"surface_chat\",\"name\":\"{{productName}} Chat\",\"type\":\"chat\",\"config\":{},\"routes\":[{\"capabilityId\":\"cap_support\"}]}],\"_meta\":{\"schemaVersion\":\"1.0\",\"catalogVersion\":\"1.0\",\"generatedAt\":\"2026-03-07T00:00:00.000Z\",\"generatorVersion\":\"1.0.0\",\"planHash\":\"import-json-example\"}},\"template\":{\"variables\":[{\"key\":\"productName\",\"label\":\"Product Name\",\"inputType\":\"text\",\"required\":true,\"defaultValue\":\"Example Organization Support Copilot\"},{\"key\":\"companyName\",\"label\":\"Company Name\",\"inputType\":\"text\",\"required\":true}]}}"
  }
}
EOF
```

The `content` string declares two template variables, `productName` and `companyName`. Only `productName` has a default value.

### Preview an A2A agent card

An A2A agent card is a JSON document with a top-level `name` and optional fields such as `description`, `url`, and `skills`. Send it as a URL or pasted JSON source, the same way as an FPO. The preview response returns `sourceType: "a2a-agent"`.

### Preview response

The preview response describes the product before anything is created. The following table lists the fields to check:

| Field                         | Source types          | Description                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ----------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `importToken`                 | All                   | Token for the reload and create requests. It expires after 30 minutes.                                                                                                                                                                                                                                                                                                                                                       |
| `sourceType`                  | All                   | `a2a-agent`, `fpo`, or `fpo-template`.                                                                                                                                                                                                                                                                                                                                                                                       |
| `preview`                     | All                   | `productName`, `description`, `capabilities` (each with `type` and `name`), `toolCount`, and `surfaceCount`.                                                                                                                                                                                                                                                                                                                 |
| `architecture`                | All                   | The agents, flows, tools, and surfaces that the create request builds.                                                                                                                                                                                                                                                                                                                                                       |
| `pendingSecrets`              | `fpo`, `fpo-template` | Credentials the product needs after import. Each entry has `source` (`tool` for a tool's `auth.secrets`, `product` for a top-level `secrets[]` entry, `reference` for a bare `{{secret:NAME}}`), `key`, `required`, and optional `description`, `placeholder`, and `docsUrl`. Entries with `source: "tool"` also carry `toolId`, `toolName`, and `toolProvider`. Present when the product declares or references any secret. |
| `template.variables`          | `fpo-template`        | The template's variables and their input types, defaults, and `required` flags.                                                                                                                                                                                                                                                                                                                                              |
| `template.defaultsSufficient` | `fpo-template`        | `true` when the default values alone produce a valid product.                                                                                                                                                                                                                                                                                                                                                                |
| `a2a`                         | `a2a-agent`           | The agent card and the product template that Runtype builds around it.                                                                                                                                                                                                                                                                                                                                                       |

If `template.defaultsSufficient` is `true`, you can create the product without a `variables` object. If `pendingSecrets` is present, have those credentials ready before you finish setup.

## Step 2: Reload a preview session

Use the `importToken` from the preview response to restore the preview after an authentication redirect or page refresh.

The following TypeScript example restores the preview session:

**`TypeScript`**

```typescript title="TypeScript"
const session = await fetch(
  'https://api.runtype.com/v1/quick-start/imports/qsi_YOUR_IMPORT_TOKEN'
).then((response) => response.json())

console.log(session.importToken)
console.log(session.architecture)
```

Replace `qsi_YOUR_IMPORT_TOKEN` with the token returned by the preview request.

The following cURL command restores the same preview session:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/quick-start/imports/qsi_YOUR_IMPORT_TOKEN
```

The response has the same shape as the preview response. Preview sessions expire after 30 minutes. When the token doesn't identify a stored session, the API returns `404` with the code `SESSION_NOT_FOUND`.

## Step 3: Create the product

Use the import token to create the product after you accept the preview.

### Create a product from a raw FPO

To create a raw FPO import, send the `importToken` in a request that includes your API key. The following TypeScript example creates the product:

**`TypeScript`**

```typescript title="TypeScript"
const createResponse = await fetch('https://api.runtype.com/v1/quick-start/create', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    importToken: 'qsi_YOUR_IMPORT_TOKEN',
  }),
})

const created = await createResponse.json()
console.log(created.redirectUrl)
```

Replace `YOUR_API_KEY` with your Runtype API key and `qsi_YOUR_IMPORT_TOKEN` with the preview token.

The following cURL command creates the same raw FPO import:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/quick-start/create \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "importToken": "qsi_YOUR_IMPORT_TOKEN"
  }'
```

### Create a product from an FPO template

To create an FPO template import, send values for required template variables that don't have defaults. The following TypeScript example sends the required values:

**`TypeScript`**

```typescript title="TypeScript"
const created = await fetch('https://api.runtype.com/v1/quick-start/create', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    importToken: 'qsi_YOUR_TEMPLATE_IMPORT_TOKEN',
    variables: {
      companyName: 'Example Organization',
    },
  }),
}).then((response) => response.json())

console.log(created.product.id)
console.log(created.redirectUrl)
```

Replace `YOUR_API_KEY` with your Runtype API key and `qsi_YOUR_TEMPLATE_IMPORT_TOKEN` with the preview token. If your template declares more variables, include their values under `variables`.

The following cURL command creates the same FPO template import:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/quick-start/create \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "importToken": "qsi_YOUR_TEMPLATE_IMPORT_TOKEN",
    "variables": {
      "companyName": "Example Organization"
    }
  }'
```

Variables with `inputType: "secret"` can't have default values. Runtype substitutes a secret variable's value into the product and stores it in the product record. To keep a credential in your secrets instead, declare it as a pending secret on the tool that uses it. For more information, see [Collect credentials](/developer-guides/guides/fpo-templates#collect-credentials).

### Create a product from an A2A agent card

An A2A import accepts an optional `productName` field that overrides the name from the agent card. The name must be 1 to 255 characters. The following cURL command creates an A2A import with a custom name:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/quick-start/create \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "importToken": "qsi_YOUR_A2A_IMPORT_TOKEN",
    "productName": "Research Assistant"
  }'
```

For an FPO or FPO template import, `productName` returns a `400` error. Set the product name in the document instead.

### Create response

A successful create returns `201`. The following table lists the response fields:

| Field                   | Type    | Description                                                                                           |
| ----------------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| `success`               | Boolean | Always `true` on success.                                                                             |
| `product`               | Object  | The new product's `id`, `name`, and `description`.                                                    |
| `capabilities`          | Array   | Each capability's `id`, `type`, and `name`, plus `agentId` or `flowId` for the agent or flow created. |
| `redirectUrl`           | String  | The dashboard path to open next. See [Step 4](#step-4-finish-setup).                                  |
| `estimatedSetupSeconds` | Number  | Estimated setup time.                                                                                 |
| `testApiKey`            | Object  | A new test API key, with `key`, `prefix`, and `limits`. Absent if the key couldn't be created.        |

Each successful create issues a new test API key. The key allows 20 executions a day and 200 in total. Store the `key` value if you plan to call the product with it.

## Step 4: Finish setup

The `redirectUrl` value is a path in the dashboard, not a full URL. To finish setup, open `https://use.runtype.com` followed by the path.

If a tool in the product needs credentials that you haven't set up yet, the path opens the secrets configuration page instead of the product. Enter the listed secrets before you test the product. For more information, see [Managing secrets](/user-guide/settings/managing-secrets).

### Required API key scopes

A dashboard session can create any import. An API key must hold the scopes for everything the product creates:

| Condition                                                                                                                   | Required scope                        |
| --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| Always                                                                                                                      | `PRODUCTS:CREATE` or `PRODUCTS:WRITE` |
| The product declares secrets (product-level `secrets`, or a tool whose `auth` has `setupRequired: true` and `secrets`)      | `SECRETS:WRITE`                       |
| A capability creates a flow                                                                                                 | `FLOWS:WRITE`                         |
| A capability creates an agent                                                                                               | `AGENTS:WRITE` or `AGENTS:CREATE`     |
| The import is an A2A agent card                                                                                             | `AGENTS:WRITE` or `AGENTS:CREATE`     |
| The import is an A2A agent card that uses the `a2a-agent` template (the default), which creates chat, API, and MCP surfaces | `PRODUCTS:SURFACES:WRITE`             |
| The product has surfaces                                                                                                    | `PRODUCTS:SURFACES:WRITE`             |
| The product has schedules                                                                                                   | `SCHEDULES:WRITE`                     |
| The product has records                                                                                                     | `RECORDS:WRITE`                       |
| The product has evals                                                                                                       | `EVALS:WRITE`                         |
| The product has skills                                                                                                      | `SKILLS:WRITE`                        |
| An HTTP flow step (`fetch-url`, `api-call`, `wait-until`, or `paginate-api`) references `{{secret:NAME}}`                   | `SECRETS:READ`                        |

Entities with `createPolicy: "skip"` do not need their scope. Test keys (`rt_test_` prefix) cannot hold `SECRETS:WRITE`, so a test key cannot create a product that declares secrets. Use a live key with `SECRETS:WRITE`, or create the product from the dashboard.

### Errors

If the request has no valid credential, the API returns HTTP 401 with the `UNAUTHORIZED` code:

```json
{
  "success": false,
  "error": "Authentication required",
  "code": "UNAUTHORIZED"
}
```

If the API key does not hold a required scope, the API returns HTTP 403 with the `FORBIDDEN` code. The `error` field names the missing scopes, and `details.missingScopes` lists them. Each inner list holds scopes of which the key needs one:

```json
{
  "success": false,
  "error": "Insufficient permissions. This FPO requires: FLOWS:WRITE, SCHEDULES:WRITE",
  "code": "FORBIDDEN",
  "details": { "missingScopes": [["FLOWS:WRITE"], ["SCHEDULES:WRITE"]] }
}
```

The API creates nothing when it returns 403.

## Create a repository button

To add a **Deploy to Runtype** link to a repository `README`, link to the import page with your document's URL in the `from` query parameter. URL-encode the document URL. The following Markdown snippet creates the link:

```md
[Deploy to Runtype](https://use.runtype.com/now?from=https%3A%2F%2Fexample.com%2FYOUR_PRODUCT.json)
```

To prefill a template variable, add a `templateParam:VARIABLE_KEY` query parameter for each value. URL-encode the colon as `%3A`. The following link prefills `companyName`:

```md
[Deploy to Runtype](https://use.runtype.com/now?from=https%3A%2F%2Fexample.com%2FYOUR_TEMPLATE.json&templateParam%3AcompanyName=Acme)
```

The import page ignores prefilled values for secret variables.

## Troubleshooting

Error responses carry a `code` field, an `error` message, and, when relevant, a `details` array. The following table lists the preview errors:

| Code                          | Cause                                                                                | Fix                                                         |
| ----------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| `FETCH_FAILED`                | Runtype couldn't reach the URL.                                                      | Check that the host is public and online.                   |
| `GITHUB_SOURCE_NOT_SUPPORTED` | The URL points to a GitHub repository, directory, or gist page.                      | Use the URL of one JSON file.                               |
| `INVALID_AGENT_CARD`          | The document isn't an agent card, FPO, or FPO template.                              | Check `details` for the fields that failed validation.      |
| `INVALID_CONTENT_TYPE`        | The URL responded with a type other than `application/json` or `text/plain`.         | Serve the file as JSON or plain text.                       |
| `INVALID_FPO_TEMPLATE`        | The document has `productObject` and `template` but isn't a valid template.          | Check `details` for the validation errors.                  |
| `INVALID_JSON`                | The source isn't valid JSON.                                                         | Validate the document with a JSON linter.                   |
| `INVALID_REQUEST`             | The request body isn't valid JSON.                                                   | Check the request body.                                     |
| `INVALID_URL`                 | The URL is malformed, doesn't use `https`, or points to a blocked address.           | Use a public `https` URL.                                   |
| `MARKDOWN_NOT_SUPPORTED`      | The URL points to a Markdown file.                                                   | Use a JSON document URL.                                    |
| `RATE_LIMITED`                | Your IP address sent too many preview requests (`429`).                              | Wait for the number of seconds in the `Retry-After` header. |
| `SOURCE_TOO_LARGE`            | The document is larger than 256 KB.                                                  | Reduce the document size.                                   |
| `URL_NOT_ACCESSIBLE`          | The URL returned an error status, such as `404` for a private file.                  | Make the file public.                                       |
| `VALIDATION_ERROR`            | The `source` object is missing, or its `kind`, `url`, or `content` field is invalid. | Check `details` for the field that failed.                  |

The following table lists the create errors:

| Status | Code                       | Cause                                                                                                             | Fix                                                                         |
| ------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `400`  | `INVALID_REQUEST`          | The body is invalid, `productName` was sent for a non-A2A import, or the template values produced an invalid FPO. | Check `error` and `details`.                                                |
| `400`  | `VALIDATION_FAILED`        | A required template variable has no value, or the product failed validation.                                      | For missing variables, send the keys listed in `details` under `variables`. |
| `401`  | `UNAUTHORIZED`             | The request has no valid API key.                                                                                 | Send `Authorization: Bearer YOUR_API_KEY`.                                  |
| `403`  | None                       | The account was created by an agent and isn't verified yet. The `error` field is `account_verification_required`. | Follow the `nextAction` in the response.                                    |
| `404`  | `IMPORT_SESSION_NOT_FOUND` | The import token expired or doesn't exist.                                                                        | Run the preview again and use the new token.                                |
| `500`  | `CREATION_FAILED`          | Runtype couldn't build the product.                                                                               | Try again. If the error repeats, contact support.                           |

## Next steps

* [FPO templates](/developer-guides/guides/fpo-templates): define reusable product templates with user-provided values.
* [Runtype MCP server](/developer-guides/integrations/runtype-mcp-server): import a product from an AI agent with the `create_product_from_example` tool and its `url` and `variables` inputs.
* [Quickstart](/developer-guides/getting-started/quickstart): make your first Runtype API call.