---
title: "Get a specific formation"
method: GET
path: "/v1/projects/{project_id}/formations/{formation_id}"
tags: ["Formations"]
---

# Get a specific formation

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

## Request

- Base URL: `https://api.naturali.ai`
- URL: `https://api.naturali.ai/v1/projects/{project_id}/formations/{formation_id}`
- 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 the formation stack including its current resources.

## Path parameters

- `formation_id` string, required

## Response `200`

Formation details

- Formation
  - `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

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found

---

[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)
