---
title: "List formations"
method: GET
path: "/v1/projects/{project_id}/formations"
tags: ["Formations"]
---

# List formations

`GET /v1/projects/{project_id}/formations`

## Request

- Base URL: `https://api.naturali.ai`
- URL: `https://api.naturali.ai/v1/projects/{project_id}/formations`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.naturali.ai/authorize`, token URL `https://api.naturali.ai/token`, scopes: `mcp:access`)

Returns all formation stacks for a project

## Query parameters

- `limit` integer
- `offset` integer

## Response `200`

List of formations

- object
  - `data` Formation[], required
    - `id` string: Public ID of the formation
    - `project_id` string: Project public ID
    - `name` string: Human-readable formation name
    - `template` FormationTemplate
      - `parameters` object, nullable: Declared parameters for this template. Each parameter may have a default value and an optional description. Parameters without a default must be supplied in the `parameters` field of the deploy request.
      - `resources` object, required: Map of logical resource IDs to resource declarations
      - `outputs` object, nullable: Map of output names to values. Values may use `{ "ref": "logicalId" }` to reference physical IDs of created resources, or `{ "param": "ParamName" }` and `{ "sub": "text ${ParamName}" }` to embed parameter values. `{ "ref_attr": "LogicalId.attribute" }` resolves a named attribute of a created resource, except one carrying credential material — a trigger's or webhook's `secret` is refused with 400 VALIDATION_FAILED, since a formation is readable by anyone holding `formations:GetFormation`. Read those from the resource's own secret route instead.
      - `metadata` NullableMetadataBag, nullable: A `MetadataBag` on a request field where `null` is meaningful: a full-replacement update that clears the bag. A record whose bag is unset leaves the field out.
    - `outputs` object, nullable: Resolved output values after stack deployment. An output that resolved a credential attribute on a formation deployed before those were refused is omitted.
    - `status` 'creating' | 'active' | 'updating' | 'failed' | 'deleting' | 'deleted' | 'delete_failed': Formation status
    - `metadata` MetadataBag: Caller-owned annotations on a resource, stored as the object they were written as: the types a value was written with are the types a read returns, so a filter can ask an ordering question about a number. Unlike other body fields, keys are stored and returned verbatim in the casing supplied — they are not converted between snake_case and camelCase. No key is reserved, and that is the point: every piece of state the platform owns lives in its own typed column, so nothing written here reaches platform state. The platform never reads the bag — it is not an IAM context, not a policy input and not part of a prompt — which is what separates it from a tag bag.
    - `resolved_metadata` object, nullable: The template's top-level `metadata` block after parameter (`sub`/`param`) and resource (`ref`) substitution at the last deploy. Null when the template declares no metadata.
    - `resolved_parameters` object, nullable: Parameter values applied at the last deploy, for auditability. `no_echo` parameters are masked (`***`). Null when the template declares no parameters.
    - `error` StoredError: Why a resource's work failed, in the shape of an error response's `error` without `hint` and `docs_url`. Every `error` field a resource records carries it, so `code` can be read without first checking the type of `error`.
      - `code` string, required: A key from the server's ERROR_CODES registry, documented on the Error Codes page. `INTERNAL_ERROR`, with the message `Internal Server Error`, records an unexpected failure whose detail reaches the server log only.
      - `message` string, required
      - `meta` object: The failure's own structured context, when it names any.
    - `resources` FormationResource[]: Resources managed by this formation (present on get/create/update)
      - `id` string: Public ID of the resource record
      - `logical_id` string: Logical identifier from the template
      - `resource_type` string: Resource type (e.g. `agent`, `memory_store`)
      - `physical_resource_id` string, nullable: Public ID of the physical the runtime resource
      - `status` 'pending' | 'created' | 'updated' | 'deleted' | 'failed': Current resource status
    - `created_at` string, date-time
    - `updated_at` string, date-time
  - `total` integer, required
  - `limit` integer, required
  - `offset` integer, required

## Other responses

- `401`: Unauthorized
- `403`: Forbidden

---

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