POST /v1/projects
Create a project, typically one per end-customer.
POST
/v1/projectsPhase 1stableidempotent
- Auth
- Bearer
- Scope
- projects:write
Create a project to hold one end-customer's brand context, layers, influencers, social accounts, and generated content. Set customerExternalId to your partner-side customer handle so later lookups don't require Layers IDs.
The call is synchronous and idempotent on id (if you create one) or on the Idempotency-Key header. It provisions the project shell; downstream ingestion (GitHub, website, App Store) is a separate, async step.
Headers
Idempotency-Keystring (UUID)optionalSame key + same body replays the cached response for 24 hours. Recommended for every POST.
Body
idstringoptionalPartner-created project ID. If omitted, the server generates one.namestringrequiredHuman-readable project name, 1–128 chars.customerExternalIdstringoptionalYour internal customer handle. Unique per organization. Looked up via ?customerExternalId=.ownerEmailstringoptionalNotification email. Defaults to the API key's registered owner.timezonestringrequiredIANA timezone. Controls cron schedule resolution. Use `"UTC"` if you have no preference.primaryLanguagestringoptionaldefault: enBCP-47 language tag (e.g. en, pt-BR).metadataobjectoptionalOpaque JSON, ≤ 8KB. Round-tripped unchanged.
Example request
curl https://api.layers.com/v1/projects \
-H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..." \
-H "Idempotency-Key: 4c1a2e92-7b18-4c4b-9b2a-d7a3f8b1c210" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Coffee iOS",
"customerExternalId": "acme-coffee",
"timezone": "America/Los_Angeles",
"primaryLanguage": "en",
"ownerEmail": "growth@gicgrowth.com"
}'const project = await layers.projects.create(
{
name: "Acme Coffee iOS",
customerExternalId: "acme-coffee",
timezone: "America/Los_Angeles",
primaryLanguage: "en",
ownerEmail: "growth@gicgrowth.com",
},
{ idempotencyKey: crypto.randomUUID() }
);project = layers.projects.create(
name="Acme Coffee iOS",
customer_external_id="acme-coffee",
timezone="America/Los_Angeles",
primary_language="en",
owner_email="growth@gicgrowth.com",
idempotency_key=str(uuid.uuid4()),
)Response
201Created
{
"id": "9cb958b5-11b5-4e30-8675-5d075d52da7c",
"organizationId": "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": null,
"ingestState": { "github": null, "website": null, "appstore": null },
"requiresApproval": false,
"firstNPostsBlocked": 3,
"currentBlockedCount": 0,
"metadata": null,
"createdAt": "2026-04-18T19:02:11.959888+00:00",
"updatedAt": "2026-04-18T19:02:11.959888+00:00"
}Errors
| Status | Code | When |
|---|---|---|
| 422 | VALIDATION | name empty, timezone invalid, metadata > 8KB. |
| 401 | UNAUTHENTICATED | Missing or invalid key. |
| 403 | FORBIDDEN_SCOPE | Key lacks projects:write. |
| 409 | CONFLICT | Same Idempotency-Key replayed with a different body, or customerExternalId already in use on another project. |
| 429 | RATE_LIMITED | Write budget exhausted. |
See also
POST /v1/projects/:id/ingest/github— seed brand context from a repoPOST /v1/projects/:id/ingest/website— seed from a landing pagePATCH /v1/projects/:id— update fields- Idempotency — replay semantics