curl -X POST https://api.vertracloud.app/v1/templates/discord-bot-js/deploy \
-H "Authorization: Bearer $VERTRA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5b0e2f6a-8d1c-4a47-9e53-3c7f1a2b6d90" \
-d '{
"name": "my-discord-bot",
"inputs": { "discord_token": "YOUR_BOT_TOKEN" },
"services": { "app": { "ram": 256 } }
}'
{
"response": {
"id": "3f6a9c12-7e4b-4d58-a1c0-5b8e2d9f7a63",
"kind": "deploy",
"template_id": "7c1d4f0e-3b8a-4d52-9a66-1f0c2e5a9b41",
"version_id": "e0b7a2c9-5d14-4f8e-8c3a-92d6b1f47a10",
"version": "1.0.0",
"status": "queued",
"current_step": null,
"steps": [
{ "step": "validate", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "apps", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "variables", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "start", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "healthcheck", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "outputs", "status": "pending", "started_at": null, "finished_at": null }
],
"error": null,
"resources": [],
"stack_id": null,
"application_id": null,
"outputs": [],
"created_at": "2026-10-28T14:00:00Z",
"updated_at": "2026-10-28T14:00:00Z",
"finished_at": null
}
}
Templates
Deploy Template
Starts a deploy job that creates, as one operation, the applications, databases and stack a template describes, and undoes everything if a step fails.
POST
/
v1
/
templates
/
{template_id}
/
deploy
curl -X POST https://api.vertracloud.app/v1/templates/discord-bot-js/deploy \
-H "Authorization: Bearer $VERTRA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5b0e2f6a-8d1c-4a47-9e53-3c7f1a2b6d90" \
-d '{
"name": "my-discord-bot",
"inputs": { "discord_token": "YOUR_BOT_TOKEN" },
"services": { "app": { "ram": 256 } }
}'
{
"response": {
"id": "3f6a9c12-7e4b-4d58-a1c0-5b8e2d9f7a63",
"kind": "deploy",
"template_id": "7c1d4f0e-3b8a-4d52-9a66-1f0c2e5a9b41",
"version_id": "e0b7a2c9-5d14-4f8e-8c3a-92d6b1f47a10",
"version": "1.0.0",
"status": "queued",
"current_step": null,
"steps": [
{ "step": "validate", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "apps", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "variables", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "start", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "healthcheck", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "outputs", "status": "pending", "started_at": null, "finished_at": null }
],
"error": null,
"resources": [],
"stack_id": null,
"application_id": null,
"outputs": [],
"created_at": "2026-10-28T14:00:00Z",
"updated_at": "2026-10-28T14:00:00Z",
"finished_at": null
}
}
Creates everything the template describes, as one asynchronous operation, and answers
If a step fails, the job moves to
202 Accepted with the job. The needed scope is templates:deploy (included in the write preset). If any step fails, the job removes everything it created, taking a safety snapshot before it deletes each app or database, and ends as failed. Follow the job with Get Deploy Job or its event stream. To use the template from the dashboard instead, see Use a template.
Only the owner of the account or of the workspace can deploy a template: a workspace member gets WORKSPACE_OWNER_ONLY, and what is created belongs to the workspace owner. An account can run one deploy at a time; a second call while one is running fails with TEMPLATE_DEPLOY_IN_PROGRESS. Before answering 202 the call already checks your answers, the destination, the memory, the plan the template requires, your limits of applications and databases, the hourly limit of deploys and the image slots.
string
required
The template ID or its slug.
string
Makes the call safe to repeat, and is recommended on every call. From 1 to 255 visible characters, unique per account. Repeating the same key with the same request returns the same job with
200 instead of creating a second set of resources. The same key with a different request fails with IDEMPOTENCY_KEY_CONFLICT.string
required
The name of the application, or of the stack when the template has more than one service. From 1 to 50 characters.
string
An optional description, up to 128 characters.
string
A version number, such as
1.1.0. It is only valid when the template lets users choose versions (TEMPLATE_VERSION_NOT_SELECTABLE otherwise). Default: the latest. See List Template Versions.object
Your answers to the questions of the template, by question ID, as text, number or boolean. The questions come from
inputs in Get Template. A required question with no answer, an answer outside its limits or a question that does not apply fails with TEMPLATE_INPUT_INVALID. Secret questions with a generator are filled by the platform when left empty. Up to 50 answers.object
Your choices per service, by service ID (up to 20 services). Each value is an object with:
name(string, 1 to 50 characters): the name of the application or database. Default: the name of the deploy followed by the service ID.ram(integer, MB): the memory, within what the template permits. It cannot be below the service minimum unless the template allows it.subdomain(string, up to 63 characters): for an application with web,"random"or the subdomain you want. A taken subdomain fails withSUBDOMAIN_TAKEN.
string
The network mode of the stack. Only
public is accepted: the stack’s applications reach its databases through their public address with client certificates. Any other value fails with STACK_NETWORK_MODE_UNAVAILABLE. See Stacks.string
The workspace that will own what is created. You must be its owner.
string
A resource folder to put the application or stack in, in the account or in the
workspace_id workspace.What the job does
The job lists only the steps that apply to the template, in this order:| Step | What happens |
|---|---|
validate | The plan, memory, limits and answers are checked again. |
network | With two or more services, the stack is created. |
databases | The databases are created and waited for. |
blob | The stack’s Blob folder and its restricted key are created. |
images | The images are made available to your account. |
apps | The applications are created. |
variables | The variables are resolved and saved. |
certificates | The client certificates of the databases are delivered to the applications. |
start | Everything is started. |
healthcheck | The platform waits for each service to answer its health check. |
outputs | The outputs shown at the end are saved. |
undoing, removes in reverse order only what it created (any Blob files are kept) and ends as failed with the readable error. An image slot the job took is released and a share link use it consumed is given back. A job with no progress for a while is picked up by the platform and undone.
Outputs
When the job succeeds, itsoutputs carry what the template wants you to see, such as the address of the application or generated credentials. An output marked once is shown only once: the first read of the finished job returns its value, and every later read returns null. Copy it then. Outputs are never sent on the event stream. Applications of a closed template keep their code hidden.
Response
Status202 with the new job. Status 200 with the same job when the Idempotency-Key was already used with the same request.
object
The job, in the
queued status. Its fields are described in Get Deploy Job: id, kind (deploy), template_id, version_id, version, status, current_step, steps, error, resources, stack_id, application_id, outputs, created_at, updated_at and finished_at.curl -X POST https://api.vertracloud.app/v1/templates/discord-bot-js/deploy \
-H "Authorization: Bearer $VERTRA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5b0e2f6a-8d1c-4a47-9e53-3c7f1a2b6d90" \
-d '{
"name": "my-discord-bot",
"inputs": { "discord_token": "YOUR_BOT_TOKEN" },
"services": { "app": { "ram": 256 } }
}'
{
"response": {
"id": "3f6a9c12-7e4b-4d58-a1c0-5b8e2d9f7a63",
"kind": "deploy",
"template_id": "7c1d4f0e-3b8a-4d52-9a66-1f0c2e5a9b41",
"version_id": "e0b7a2c9-5d14-4f8e-8c3a-92d6b1f47a10",
"version": "1.0.0",
"status": "queued",
"current_step": null,
"steps": [
{ "step": "validate", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "apps", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "variables", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "start", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "healthcheck", "status": "pending", "started_at": null, "finished_at": null },
{ "step": "outputs", "status": "pending", "started_at": null, "finished_at": null }
],
"error": null,
"resources": [],
"stack_id": null,
"application_id": null,
"outputs": [],
"created_at": "2026-10-28T14:00:00Z",
"updated_at": "2026-10-28T14:00:00Z",
"finished_at": null
}
}
Error Responses
string
The error code indicating the reason for the failure. Possible values:
VALIDATION_ERROR: The body or theIdempotency-Keyis not valid (400).TEMPLATE_INPUT_INVALID: An answer is missing or invalid, or a service choice is outside what the template allows;details.issueslists the questions (400). A malformed subdomain is reported asINVALID_SUBDOMAIN_FORMATorSUBDOMAIN_FORBIDDEN(400).STACK_NETWORK_MODE_UNAVAILABLE:network_modeis notpublic(400).TEMPLATE_RAM_INSUFFICIENT: Not enough free memory for the template;detailscarries the reasons (400).API_KEY_SCOPE_DENIED: The API key does not have thetemplates:deployscope (403).PLAN_REQUIRED: The account has no plan (403).TEMPLATE_PLAN_REQUIRED: Your plan is below what the template needs;details.reasonsanddetails.required_plansay why (403).TEMPLATE_IMAGE_SLOTS_EXHAUSTED: The template runs an image and every image slot of your plan is in use (403).MAX_APPS_REACHED,MAX_DATABASES_REACHED: The deploy would exceed your plan’s limit of applications or databases (403).TEMPLATE_DEPRECATED: The template is deprecated and cannot be used for new applications (409).TEMPLATE_VERSION_NOT_SELECTABLE: The template does not allow choosing a version (400).WORKSPACE_OWNER_ONLY: Only the owner of the workspace can use templates in it (403). A workspace template deploys only inside its own workspace: withworkspace_idof another workspace, or none, it answersTEMPLATE_NOT_FOUND(404).TEMPLATE_NOT_FOUND: The template does not exist or is not visible to you (404).TEMPLATE_VERSION_NOT_FOUND: The template has no ready version with that number (404).WORKSPACE_NOT_FOUND: The workspace does not exist or you are not part of it (404).WORKSPACE_RESOURCE_FOLDER_NOT_FOUND: The folder does not exist (404).TEMPLATE_DEPLOY_IN_PROGRESS: Another deploy of your account is running (409).IDEMPOTENCY_KEY_CONFLICT: TheIdempotency-Keywas already used with a different request (409).SUBDOMAIN_TAKEN: A chosen subdomain is already in use (409).DEPLOY_RATE_LIMITED: The hourly limit of deploys was reached (429).RATE_LIMIT_EXCEEDED: Too many requests (429).INTERNAL_SERVER_ERROR: Unexpected failure (500).
202 is not returned here: it ends the job as failed, with the code in error.code. See Get Deploy Job.{
"code": "TEMPLATE_PLAN_REQUIRED",
"details": {
"reasons": [{ "reason": "min_plan", "required": "intermediary", "available": "economy" }],
"required_plan": "intermediary"
}
}
Last modified on October 28, 2026