# GET /v1/projects/:id (/docs/api/reference/projects/get-project)



<Endpoint method="GET" path="/v1/projects/:id" auth="Bearer" scope="projects:read" phase="1" />

Returns the full project record: brand context resolved from ingestion, the layers attached to it, current approval policy, and the state of each ingestion source (GitHub, website, App Store). This is the endpoint to call when your UI needs to render a project detail page.

The project must belong to your key's organization; cross-org reads return `404 NOT_FOUND` rather than revealing the project exists.

<Parameters
  title="Path"
  rows="[
  { name: 'id', type: 'string', required: true, description: 'Project ID.' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl https://api.layers.com/v1/projects/prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39 \
      -H "Authorization: Bearer lp_..."
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const project = await layers.projects.get("prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39");
    ```
  </Tab>

  <Tab value="Python">
    ```python
    project = layers.projects.get("prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39")
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="OK">
  ```json
  {
    "id": "9cb958b5-11b5-4e30-8675-5d075d52da7c",
    "organizationId": "org_2481fa5c-a404-44ed-a561-565392499abc",
    "name": "Acme Coffee iOS",
    "status": "active",
    "customerExternalId": "acme-coffee",
    "timezone": "America/Los_Angeles",
    "primaryLanguage": "en",
    "ownerEmail": "growth@gicgrowth.com",
    "brand": null,
    "brandContext": {
      "appName": "Acme Coffee",
      "appDescription": "Pre-order your neighborhood coffee shop's daily brew.",
      "tagline": "Skip the line, keep the ritual.",
      "audience": "Urban professionals, 25–45",
      "icp": "Mobile-first coffee loyalists",
      "brandVoice": "Friendly, unfussy, a little wry",
      "keywords": ["coffee", "order ahead", "mobile payments"],
      "primaryLanguage": "en",
      "logoUrl": "https://media.layers.com/.../logo.png"
    },
    "platformIosBundleId": "com.acme.coffee",
    "platformAndroidBundleId": "com.acme.coffee.android",
    "platformWebDomain": "acmecoffee.com",
    "ingestState": {
      "github": { "status": "completed", "jobId": "job_01HXA1NHKJ...", "completedAt": "2026-04-10T09:19:33Z" },
      "website": null,
      "appstore": { "status": "completed", "completedAt": "2026-04-10T09:21:02Z" }
    },
    "metadata": null,
    "createdAt": "2026-04-10T09:14:22.000000+00:00",
    "updatedAt": "2026-04-15T17:01:09.000000+00:00"
  }
  ```

  Notes on shape:

  * `policy`, `firstN`, `pendingCount` are flat fields (not nested under `approvalPolicy`).
  * `brand` is reserved for the project's brand record; `null` until a brand is attached.
  * The `layers` collection is read separately via the project layers endpoint - it is not embedded in this response.
  * `platformIosBundleId`, `platformAndroidBundleId`, `platformWebDomain` are populated by the matching `POST /v1/projects/:id/ingest/{appstore,website}` jobs. They are read-only on this endpoint — partners cannot set them via `PATCH /v1/projects/:id`. Downstream features (CAPI configuration, Apple Search Ads, deep-link routing) gate on these values, so the recommended flow is: create project → run ingest job → poll until `completed` → re-fetch project to read the populated identifiers.
</Response>

## Errors [#errors]

| Status | Code              | When                                                                                                   |
| ------ | ----------------- | ------------------------------------------------------------------------------------------------------ |
| 401    | `UNAUTHENTICATED` | Missing or invalid key.                                                                                |
| 403    | `FORBIDDEN_SCOPE` | Key lacks `projects:read`.                                                                             |
| 404    | `NOT_FOUND`       | Project does not exist, or it lives in another organization, or `X-Layers-Customer-Id` does not match. |
| 422    | `VALIDATION`      | `:id` is not a UUID. The path parameter is validated pre-flight; non-UUIDs never reach the database.   |
| 429    | `RATE_LIMITED`    | Read budget exhausted.                                                                                 |

## See also [#see-also]

* [`PATCH /v1/projects/:id`](/docs/api/reference/projects/patch-project) - update fields
* [`GET /v1/projects/:id/events`](/docs/api/reference/telemetry/events) - SDK event stream
* [Approval concept](/docs/api/concepts/content-review) - how `approvalPolicy` gates publishes
