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

# Create a Private Template

> Creates a private template and its first version from a manifest and the code of each service, sent as multipart form data.

This call creates a private template with its first version and answers `201` with the template. The request is `multipart/form-data`: the manifest goes in a text field, and every service that runs your code goes in a ZIP part. To start from an application or a stack you already have, use [Create Template from App](https://docs.vertracloud.app/api-reference/endpoint/templates/create-from-app.md) or [Create Template from Stack](https://docs.vertracloud.app/api-reference/endpoint/templates/create-from-stack.md).

Needs the `templates:write` scope when called with an API key. Only plans that can create custom Docker images can create templates, and each account holds at most 5 private templates, personal and workspace ones together. In a workspace, only the workspace owner creates templates. A private template is not reviewed by Vertra Cloud: whoever receives it sees the notice "Not verified by Vertra". Check the manifest first with [Validate Manifest](https://docs.vertracloud.app/api-reference/endpoint/templates/validate.md). The format is in the [manifest reference](https://docs.vertracloud.app/templates/create/manifest-reference.md).

The ZIP of a service is checked before it is stored. The whole upload is refused with `TEMPLATE_SECRET_IN_SOURCE` when it holds a `.env` file that is not an example, a private key or a known token; `details.files` lists only the paths. `.vertra/` folders are dropped, and `.env*` files never enter a template.

**manifest** `string` *required*

The manifest as a JSON-serialized string, following the [manifest schema](https://docs.vertracloud.app/templates/reference/manifest-schema.md). A service whose `source.type` is `image` refers to an image of your account by its ID in `source.image`.

**sources\[service\_id]** `file`

One ZIP part per service of the manifest whose source is `code`, named after the service id, for example `sources[bot]`. Required for each of those services.

**changelog** `string`

The message of the first version, as a JSON-serialized object with `pt-br` (required), `en` and `es`.

**workspace\_id** `string`

The workspace that will own the template. Without it, the template belongs to you.

```bash cURL theme={null}
curl -X POST https://api.vertracloud.app/v1/templates \
  -H "Authorization: Bearer $VERTRA_API_KEY" \
  -F 'manifest=<manifest.json' \
  -F 'sources[bot]=@bot.zip'
```

### Response

**response** `object`

The template, with its first version.

**Toggle object**

**id** `string`

The template ID.

**slug** `string`

The template slug, taken from the `id` of the manifest.

**origin** `string`

`private` for the templates you create. Catalog templates are `vertra` or `community`.

**visibility** `string`

`public`, `beta`, `hidden` or `deprecated`.

**name** `object`

The name by language: `pt-br`, `en` and `es`. A missing `en` or `es` falls back to `pt-br`.

**description** `object`

The description by language, same shape as `name`.

**category** `string`

`automation`, `ai-agents`, `bots`, `apis`, `cms`, `monitoring`, `starters`, `databases` or `other`.

**tags** `string[]`

The tags.

**icon\_url** `string | null`

URL of the icon, or `null` when the template has none.

**author\_display** `string | null`

The name shown as the author. `null` for templates made by the platform.

**links** `object`

Links of the software the template packages: `website`, `docs`, `source` and `license`, all optional.

**landing** `string | null`

Slug of a dedicated public page, or `null`.

**featured** `boolean`

Highlighted in the gallery.

**current\_version** `object`

The latest version: `id`, `version` (semantic version), `security` (`true` for a security release) and `created_at`.

**services** `object[]`

What the template creates. Each service has `id`, `kind` (`app`, `database` or `blob`), `source_type` (`code`, `image` or `null`), `database` (the engine, or `null`), `blob_visibility`, `ram` (`min`, `recommended` and optional `max`, in MB), `web` (`required`, `optional`, `none` or `null`) and `conditional` (`true` when the service is created only for some answers).

**creates\_stack** `boolean`

`true` when using the template creates a stack (two or more services).

**ram\_min\_total** `integer`

The sum of the minimum memory of every service, in MB.

**byok** `boolean`

`true` when whoever uses the template brings their own key for an AI model.

**required\_plan** `string`

The lowest plan that can use the template.

**code\_view** `boolean`

`false` for a [closed template](https://docs.vertracloud.app/templates/use/closed-templates.md): whoever uses it cannot see its code.

**uses\_count** `integer | null`

Always `null` for a private template.

**owner** `object | null`

`user_id` and `workspace_id` (`null` when the template belongs to the user).

**github** `object | null`

The linked repository (`repository` as `owner/name`, and `branch`), or `null` when the template is not linked.

**inputs** `object[]`

The questions the user answers when using the template. See [Placeholders and inputs](https://docs.vertracloud.app/templates/create/placeholders-and-inputs.md).

**permissions** `object`

The effective permissions of the apps created from the template, after defaults and the restrictions of a closed template: `code_view`, `code_edit`, `ram_change`, `ram_below_min`, `ram_above_max`, `env_add`, `commands_edit`, `terminal`, `save_as_template` and `detach`, all booleans.

**outputs** `object[]`

What the wizard shows at the end of a deploy: `label`, `value` and the optional flags `secret` and `once`.

**readme** `object | null`

The documentation of the template (Markdown) by language, or `null`.

**changelog** `object | null`

The changelog of the latest version by language, or `null`.

**account** `object`

What using the template would do to your account (`fits`, `reasons`, `required_ram`, `free_ram`, `needs_image_slot`, `image_slots_free`, `in_use`, `in_use_count`). Present only on calls that are authenticated and read the template.

**created\_at** `string`

When the template was created.

**updated\_at** `string`

When the template was last updated.

```json Response theme={null}
{
  "response": {
    "id": "tpl-abc123def456",
    "slug": "support-bot",
    "origin": "private",
    "visibility": "public",
    "name": { "pt-br": "Bot de suporte", "en": "Support bot" },
    "description": { "pt-br": "Bot que responde o suporte.", "en": "A bot that answers support." },
    "category": "bots",
    "tags": ["discord", "support"],
    "icon_url": null,
    "author_display": "Ana",
    "links": {},
    "landing": null,
    "featured": false,
    "current_version": {
      "id": "tplv-111222333444",
      "version": "1.0.0",
      "security": false,
      "created_at": "2026-10-27T14:02:00Z"
    },
    "services": [
      {
        "id": "bot",
        "kind": "app",
        "source_type": "code",
        "database": null,
        "blob_visibility": null,
        "ram": { "min": 256, "recommended": 512 },
        "web": "none",
        "conditional": false
      }
    ],
    "creates_stack": false,
    "ram_min_total": 256,
    "byok": false,
    "required_plan": "economy",
    "code_view": true,
    "uses_count": null,
    "owner": { "user_id": "1234567890123456789", "workspace_id": null },
    "github": null,
    "inputs": [],
    "permissions": {
      "code_view": true,
      "code_edit": true,
      "ram_change": true,
      "ram_below_min": false,
      "ram_above_max": true,
      "env_add": true,
      "commands_edit": true,
      "terminal": false,
      "save_as_template": true,
      "detach": true
    },
    "outputs": [],
    "readme": null,
    "changelog": null,
    "created_at": "2026-10-27T14:02:00Z",
    "updated_at": "2026-10-27T14:02:00Z"
  }
}
```

### Error Responses

**code** `string`

The error code indicating the reason for the failure. Possible values:

* `API_KEY_SCOPE_DENIED`: The API key does not have the `templates:write` scope (`403`).
* `TEMPLATE_MANIFEST_INVALID`: The manifest is not valid; `details.issues` lists each finding with its `path` and `code`. Nothing is created.
* `TEMPLATE_SOURCE_REQUIRED`: A `code` service has no ZIP part.
* `TEMPLATE_SECRET_IN_SOURCE`: A ZIP holds a secret (an `.env` file, a private key or a token); `details.files` lists the paths (`400`).
* `TEMPLATE_SLUG_TAKEN`: The `id` of the manifest is already in use among your templates or is a reserved word.
* `TEMPLATE_PRIVATE_LIMIT_REACHED`: The account already has 5 private templates.
* `PLAN_DOES_NOT_SUPPORT_CUSTOM_IMAGES`: The plan cannot create custom Docker images, so it cannot create templates.
* `IMAGE_NOT_FOUND`: An `image` service refers to an image that is not yours or has no successful build.
* `WORKSPACE_OWNER_ONLY`: `workspace_id` was sent and the caller is not the owner of that workspace.

```json Error Response theme={null}
{
  "code": "TEMPLATE_MANIFEST_INVALID",
  "details": {
    "issues": [{ "path": "services.bot.ram.min", "code": "invalid_ram", "message": "ram.min must be a positive number of MB" }]
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.