---
title: "Install a template"
method: POST
path: "/v1/installs"
tags: ["Installs"]
---

# Install a template

`POST /v1/installs`

## Request

- Base URL: `https://api.banksync.io`
- URL: `https://api.banksync.io/v1/installs`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Install a template into this workspace. Answers at once with the install `installing`; it finishes in the background — poll `GET /installs/{installId}`. A resource that fails leaves the install `partial` (retry with `PATCH`, `action: "retry"`). Automations arrive switched off. 50 installs an hour per workspace; an unverified listing installs into at most ten workspaces (`INSTALL_CAP_REACHED`); a template that needs more tables, feeds or enrichments than the plan has left is refused (`PLAN_LIMIT_REACHED`, the same caps as creating them by hand).

## Headers

- `Idempotency-Key` string: Makes a retry safe: the same key with the same request replays the first answer for 24 hours instead of running twice, and the same key with a different request is a 409 `IDEMPOTENCY_KEY_REUSED`. Refusals a retry can outlive — 408, 409, 423, 425, 429 and every 5xx — are never replayed, so retrying with the same key after the cause clears runs the request.

## Request body

- object
  - `source` 'listing' | 'workspace' | 'preset' | 'inline', required: `listing` (with `listingId`), `workspace` (a saved blueprint, `blueprintId`), `preset` (`presetKey`) or `inline` (`blueprint`)
  - `listingId` string: From `GET /marketplace/listings`
  - `releaseId` string: A specific release of the listing; default its current approved release
  - `linkToken` string: The private-link token (the `?link=` value of the private link) of a listing that is not publicly listed; required to install one
  - `blueprintId` string
  - `presetKey` string
  - `blueprint` object: A portable blueprint
  - `bindings` object: Slot id → binding: `{"kind":"bank","bankId"}`, `{"kind":"feed","feedId"}`, `{"kind":"connection","integrationId"}`, `{"kind":"container","destination"}`, `{"kind":"resource","id"}` or `{"kind":"value","value"}`. The plan lists each slot and what answers it.
  - `resourceKeys` string[]: Install only these resources (by key) and what they need
  - `name` string: Default: the template’s title, numbered when one of that name exists
  - `timeZone` string: The installing person’s IANA time zone (Australia/Sydney): a template automation scheduled in the installer’s zone runs in it when the workspace keeps none. Default: UTC

## Response `201`

The install

- object
  - `success` true, required
  - `data` object, required
    - `install` object, required
      - `id` string, required: Install id — the `installId` other operations take
      - `name` string, required
      - `source` 'listing' | 'app' | 'workspace' | 'preset' | 'inline', required
      - `listingId` string, nullable, required
      - `releaseId` string, nullable, required
      - `blueprintId` string, nullable, required
      - `blueprintKey` string, nullable, required
      - `status` 'installing' | 'installed' | 'partial' | 'removing' | 'removed', required
      - `generation` integer, required
      - `error` string, nullable, required
      - `createdAt` string, nullable, required
      - `updatedAt` string, nullable, required
      - `removedAt` string, nullable, required
      - `removeMode` 'keep' | 'trash' | 'null', nullable, required
      - `planIncludesMore` boolean
      - `bindings` object, required
    - `resources` object[], required
      - `key` string, required
      - `kind` string, required
      - `resourceId` string, nullable, required
      - `mode` 'created' | 'adopted' | 'linked', required
      - `status` 'pending' | 'created' | 'skipped' | 'failed' | 'removed', required
      - `userModified` boolean, required
      - `error` string, nullable, required
      - `appliedAt` string, nullable, required
      - `keptFor` object: A removed row whose resource stays because another install still uses it (a shared table, feed or enrichment)
        - `installId` string, required
        - `installName` string, required
      - `sharedWith` object[]: installs_get: the other live installs that also use this shared table, feed or enrichment. Removing this install (either mode) keeps it for them — it is never trashed while one of them uses it
        - `installId` string, required
        - `installName` string, required
    - `planIncludedNow` object[]
      - `resourceKey` string, required
      - `kind` string, required
      - `name` string, required
      - `plan` string, required: The lowest plan that includes it (`professional`)
      - `planLabel` string, required
      - `adds` string, required: What it adds, in words ("AI categorising")
      - `reason` string, required: "Included on Professional: AI categorising"
      - `requirement` 'count': `count`: what the template makes needs more of a capped thing (tables, a bank connection) than lower plans allow, so it needs this plan to install. Absent: a plan-gated step, skipped below its plan.
    - `dispatch` 'started' | 'deferred', required: `started`: the install runs now; poll installs_get. `deferred`: the run could not be started this moment; it starts within the hour without another call.

## Other responses

- `400`: Invalid input — `code` names it: `VALIDATION_FAILED`, `INVALID`, `INVALID_BLUEPRINT` (not a blueprint this workspace can read), `PORTABILITY_VIOLATION` (it still carries workspace ids), `UNSAFE_BLUEPRINT`, `INVALID_BINDINGS` (an input is missing or does not fit), `RESTORE_WINDOW_PASSED`; `details[]` names each field
- `401`: Unauthorized
- `403`: Forbidden — a missing `marketplace:read` / `marketplace:write` scope, a role below editor for a change, an installed app outside the public marketplace, an unverified listing already installed in ten workspaces (`INSTALL_CAP_REACHED`), or a template that needs more tables, feeds or enrichments than the workspace plan has left (`PLAN_LIMIT_REACHED`)
- `404`: Not found — something this workspace may not see answers exactly as something that does not exist; or the marketplace is not enabled for this workspace
- `409`: Conflict — it changed since you read it (`STALE`), it is busy or in the wrong state (`INVALID_STATE`), the listing cannot be installed (`NOT_INSTALLABLE`), a key is taken (`KEY_TAKEN`), or an existing container does not fit (`ADOPTION_CONFLICT`)
- `429`: Too many — the key’s rate limit, or a marketplace quota (`QUOTA_EXCEEDED`: 200 saved templates per workspace, 50 installs per hour). `Retry-After` says when to come back.
- `503`: The marketplace is temporarily unavailable; retry shortly

---

[API](https://skmtc.dev/banksync/apis/banksync-api.md) · [All operations](https://skmtc.dev/banksync/apis/banksync-api/llms.txt) · [OpenAPI document](https://skmtc.dev/banksync/apis/banksync-api/revisions/94465f5ee922?raw)
