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

# Create a Template and start its initial Build

> Creates a logical Template together with its initial Build. GMI creates
and starts the initial Build from the required `build` definition in the
same request.

`Idempotency-Key` is required and acts as the idempotency key because provider
creation can complete after an upstream timeout; a keyless retry would build a
second Template. Repeating the request with identical parameters replays the
same Template/Build (with `Idempotency-Replayed: true`); a different body under
the same key returns 400 `Sandbox.IdempotentParameterMismatch`; after the
Template is deleted the key answers 409 `Sandbox.IdempotentKeyConsumed`. Keys
are remembered for 24 hours. (`X-Request-ID` is trace-only and server-generated.)

`resources` supports two mutually exclusive forms:

- Preset: `{"type":"preset","product":"gmi.sandbox.x-large"}`. The
  `product` value is the catalog SKU (see `GET /api/v2/products`); the
  service resolves the active entry from the product catalog. Preset values are used as configured and
  are not constrained by custom resource limits.
- Custom: `{"type":"custom","cpu_count":4,"memory_mb":8192,
  "disk_size_mb":32768,"architecture":"x86_64"}`. All three numeric
  fields are required. Custom resources are limited to 16 vCPU,
  65536 MiB memory, and 65536 MiB boot disk, and must also be
  representable by the selected IDC.




## OpenAPI

````yaml /api-spec/sandbox_api.yaml post /templates
openapi: 3.0.3
info:
  title: GMI Sandbox API
  description: >-
    REST API for GMI Sandbox: create isolated execution environments from
    templates, manage their lifecycle on the control plane, and run commands or
    transfer files through each sandbox's own data plane.
  contact:
    name: GMI Cloud Support
    email: support@gmicloud.ai
  version: '2.0'
servers:
  - url: https://console.gmicloud.ai/api/v2
    description: Control plane
security:
  - bearerAuth: []
tags:
  - name: Sandbox
    description: |
      Sandbox instance lifecycle management (Sandbox v2, /api/v2/sandboxes)
  - name: SandboxTemplate
    description: Sandbox template management (Sandbox v2, `/api/v2/templates`)
  - name: Sandbox-Exec
    description: >
      Sandbox execution data plane (accessed via the sandbox host and sandbox
      access token). These endpoints are not under the control plane's `/api/v2`
      path; clients connect directly to `https://{sandbox_key}.{domain}` and
      authenticate with `X-Access-Token`.
  - name: Sandbox-Files
    description: >
      Sandbox file data plane (`/files`). **These endpoints are not under
      `/api/v2`** and do not use `Authorization: Bearer`: they are served by the
      sandbox's own data-plane entry point — clients connect directly to
      `https://{sandbox_key}.{domain}` and authenticate with `X-Access-Token`.
      `{sandbox_key}` is the `sandbox_key` returned by the create/connect
      endpoints, used for data-plane host addressing. `{domain}` and
      `X-Access-Token` are the `domain` and `sandbox_access_token` from the same
      responses — no extra endpoint is needed to obtain them.


      This split is not historical baggage but the nature of a data plane: file
      transfer is long-lived, high-volume, and addressed per sandbox, differing
      from the control plane's short requests in both capacity model and failure
      domain, so they do not share an entry point.


      **One unified abstraction.** The same contract is served by two backend
      kinds (an in-sandbox file service / a data-center data-plane proxy);
      clients need not — and cannot — tell them apart. The cost is that the
      contract is their intersection: `Content-Length` on download and resumable
      download (`Range`/`206`) are **optional capabilities** that vary by data
      center, and clients must work correctly when they are absent. See the
      per-operation notes below.
paths:
  /templates:
    post:
      tags:
        - SandboxTemplate
      summary: Create a Template and start its initial Build
      description: >
        Creates a logical Template together with its initial Build. GMI creates

        and starts the initial Build from the required `build` definition in the

        same request.


        `Idempotency-Key` is required and acts as the idempotency key because
        provider

        creation can complete after an upstream timeout; a keyless retry would
        build a

        second Template. Repeating the request with identical parameters replays
        the

        same Template/Build (with `Idempotency-Replayed: true`); a different
        body under

        the same key returns 400 `Sandbox.IdempotentParameterMismatch`; after
        the

        Template is deleted the key answers 409 `Sandbox.IdempotentKeyConsumed`.
        Keys

        are remembered for 24 hours. (`X-Request-ID` is trace-only and
        server-generated.)


        `resources` supports two mutually exclusive forms:


        - Preset: `{"type":"preset","product":"gmi.sandbox.x-large"}`. The
          `product` value is the catalog SKU (see `GET /api/v2/products`); the
          service resolves the active entry from the product catalog. Preset values are used as configured and
          are not constrained by custom resource limits.
        - Custom: `{"type":"custom","cpu_count":4,"memory_mb":8192,
          "disk_size_mb":32768,"architecture":"x86_64"}`. All three numeric
          fields are required. Custom resources are limited to 16 vCPU,
          65536 MiB memory, and 65536 MiB boot disk, and must also be
          representable by the selected IDC.
      operationId: createTemplate
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyRequiredParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTemplateRequest'
      responses:
        '201':
          description: |
            The Template record is created and immediately addressable: `GET
            /templates/{id}` works right away, and a failed initial Build
            leaves a rebuildable Template rather than erasing it. Build
            readiness is reported by `status`, not by the status code.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateMutationAccepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unsupported'
        '429':
          $ref: '#/components/responses/QuotaExceeded'
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          $ref: '#/components/responses/ProviderError'
components:
  parameters:
    IdempotencyKeyRequiredParam:
      name: Idempotency-Key
      in: header
      required: true
      description: |
        Caller-generated key that makes the mutation safe to retry (a UUID is
        recommended). Matched byte-for-byte: 1-64 printable ASCII characters,
        no whitespace. The same key with a different request body returns 400
        Sandbox.IdempotentParameterMismatch. Echoed on responses; replays add
        Idempotency-Replayed: true. Keys are remembered for 24 hours.
      schema:
        type: string
        minLength: 1
        maxLength: 64
  schemas:
    CreateTemplateRequest:
      type: object
      additionalProperties: false
      required:
        - name
        - resources
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 64
          pattern: ^[A-Za-z0-9_-]+$
          description: Organization-scoped Template display name.
        description:
          type: string
          maxLength: 256
          description: Human-readable Template description.
        idc_name:
          type: string
          description: >
            IDC that permanently owns the Template. Optional: omitted, empty,
            and whitespace-only values are equivalent — the organization's
            configured default data center is used (maintained by the platform
            administrator; the same setting used by sandbox creation). If the
            organization has no default configured, the request returns 400.
        resources:
          $ref: '#/components/schemas/ResourceSelection'
        labels:
          type: object
          maxProperties: 64
          description: User-defined labels used for filtering.
          additionalProperties:
            type: string
            maxLength: 256
        build:
          allOf:
            - $ref: '#/components/schemas/BuildDefinition'
          description: |
            Initial Build definition created and started with the Template
            (combined flow, every IDC supports it). Omitting `build` selects the
            split flow: the Template and a `waiting` initial Build are created
            without starting anything, and the Build is started later via
            `POST /templates/{template_id}/builds/{id}`. The split flow is not
            supported in every IDC; unsupported IDCs reject it with 422.
    TemplateMutationAccepted:
      type: object
      additionalProperties: false
      required:
        - request_id
        - data
      properties:
        request_id:
          type: string
          description: HTTP request correlation identifier.
        data:
          type: object
          additionalProperties: false
          required:
            - id
            - build_id
            - status
          properties:
            id:
              type: string
              description: Created GMI Template identifier.
            build_id:
              type: string
              description: Created initial or snapshot Build identifier.
            status:
              $ref: '#/components/schemas/BuildStatus'
    ResourceSelection:
      oneOf:
        - $ref: '#/components/schemas/PresetResourceSelection'
        - $ref: '#/components/schemas/CustomResourceSelection'
      discriminator:
        propertyName: type
        mapping:
          preset:
            $ref: '#/components/schemas/PresetResourceSelection'
          custom:
            $ref: '#/components/schemas/CustomResourceSelection'
      description: |
        Resource values may be selected by catalog product SKU or supplied as a
        custom configuration. Active presets use operator-managed IDC product
        values without custom-resource limit validation. Only custom values
        must pass the 16 vCPU / 64 GiB memory / 64 GiB boot disk limits and the
        selected IDC's representability checks.
    BuildDefinition:
      type: object
      additionalProperties: false
      required:
        - source
      properties:
        source:
          $ref: '#/components/schemas/BuildSource'
        commands:
          type: array
          maxItems: 100
          description: Shell command strings executed sequentially during the Build.
          items:
            type: string
            minLength: 1
            maxLength: 8192
        envs:
          type: object
          maxProperties: 256
          additionalProperties:
            type: string
            maxLength: 32768
          description: >
            Environment variables available only during the Template Build.

            They are visible to subsequent build commands/steps and are not
            persisted

            into the resulting template artifact as sandbox runtime environment

            variables. Pass runtime env when creating a Sandbox instead.
            Write-only:

            values are never returned on Template or TemplateBuild responses.

            Keys must be unique (JSON object); the server orders them

            deterministically by key. Key names must match

            `[A-Za-z_][A-Za-z0-9_]*`.
        start_cmd:
          type: string
          minLength: 1
          maxLength: 8192
          description: |
            Launch command persisted with the Build and applied when Sandboxes
            created from this Template start.
    BuildStatus:
      type: string
      enum:
        - waiting
        - building
        - ready
        - error
      description: Normalized Template Build status.
    ErrorResponse:
      type: object
      required:
        - code
        - message
        - request_id
      properties:
        code:
          type: string
          description: Machine-readable business error code
          example: Resource.QuotaExceeded
        message:
          type: string
          description: Human-readable error description
          example: The resource quota is not enough.
        request_id:
          type: string
          description: Tracing ID
          example: req-xxxx
        details:
          type: object
          description: Field-level error details
          additionalProperties: true
    PresetResourceSelection:
      type: object
      additionalProperties: false
      required:
        - type
        - product
      properties:
        type:
          type: string
          enum:
            - preset
        product:
          type: string
          description: |
            Sandbox product specification id (catalog SKU, for example
            `gmi.sandbox.x-large`).
    CustomResourceSelection:
      type: object
      additionalProperties: false
      required:
        - type
        - cpu_count
        - memory_mb
        - disk_size_mb
      properties:
        type:
          type: string
          enum:
            - custom
        cpu_count:
          type: integer
          minimum: 1
          maximum: 16
          description: |
            Requested integer vCPU count. Custom resources allow at most
            16 vCPU.
        memory_mb:
          type: integer
          minimum: 1
          maximum: 65536
          description: |
            Requested integer memory size in MiB. Custom resources allow at
            most 65536 MiB (64 GiB).
        disk_size_mb:
          type: integer
          minimum: 1
          maximum: 65536
          description: |
            Requested integer boot disk size in MiB. Custom resources allow at
            most 65536 MiB (64 GiB).
        architecture:
          type: string
          enum:
            - x86_64
            - arm64
          default: x86_64
          description: |
            Requested CPU architecture. If omitted, x86_64 is used. The
            selected IDC must support the value.
    BuildSource:
      oneOf:
        - $ref: '#/components/schemas/ImageSource'
        - $ref: '#/components/schemas/TemplateSource'
      discriminator:
        propertyName: type
        mapping:
          image:
            $ref: '#/components/schemas/ImageSource'
          template:
            $ref: '#/components/schemas/TemplateSource'
      description: Manual Build source. Sandbox sources use the snapshot endpoint.
    ImageSource:
      type: object
      additionalProperties: false
      required:
        - type
        - image
      properties:
        type:
          type: string
          enum:
            - image
        image:
          type: string
          minLength: 1
          description: |
            Debian or Ubuntu container image reference. The server validates
            the image against the IDC-supported base OS policy.
    TemplateSource:
      type: object
      additionalProperties: false
      required:
        - type
        - template_id
      properties:
        type:
          type: string
          enum:
            - template
        template_id:
          type: string
          description: Parent GMI Template identifier in the same IDC.
        build_id:
          type: string
          description: |
            Optional parent Build identifier. When omitted, the parent's
            current successful Build is used.
  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: Parameter.Invalid
            message: Invalid request parameters
            request_id: req-xxxx
    Unauthorized:
      description: Unauthenticated
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: Auth.Unauthorized
            message: Authentication required
            request_id: req-xxxx
    Forbidden:
      description: The caller cannot access the organization-scoped resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: State conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: Resource.StateConflict
            message: Resource state conflict
            request_id: req-xxxx
    Unsupported:
      description: |
        The request is valid but the selected IDC or provider does not support
        the requested capability or resolved resource specification.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    QuotaExceeded:
      description: The configured or temporary resource quota would be exceeded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: Internal.ServerError
            message: An internal server error occurred
            request_id: req-xxxx
    ProviderError:
      description: The selected Sandbox provider is unavailable or returned an error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        API Key or Access Token, always sent as `Authorization: Bearer <token>`.
        The gateway recognizes the token type automatically.

````