GET /v1/projects/:id
Retrieve a project, including brand context, layers, and approval policy.
GET
/v1/projects/:idPhase 1stable
- Auth
- Bearer
- Scope
- projects:read
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.
Path
idstringrequiredProject ID.
Example request
curl https://api.layers.com/v1/projects/prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39 \
-H "Authorization: Bearer lp_..."const project = await layers.projects.get("prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39");project = layers.projects.get("prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39")Response
200OK
{
"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,pendingCountare flat fields (not nested underapprovalPolicy).brandis reserved for the project's brand record;nulluntil a brand is attached.- The
layerscollection is read separately via the project layers endpoint - it is not embedded in this response. platformIosBundleId,platformAndroidBundleId,platformWebDomainare populated by the matchingPOST /v1/projects/:id/ingest/{appstore,website}jobs. They are read-only on this endpoint — partners cannot set them viaPATCH /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 untilcompleted→ re-fetch project to read the populated identifiers.
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
PATCH /v1/projects/:id- update fieldsGET /v1/projects/:id/events- SDK event stream- Approval concept - how
approvalPolicygates publishes