> ## Documentation Index
> Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Use Stable documentation by default. Honor an explicit Beta request or a URL under /docs/beta/. If the requested version conflicts with the installed CLI package or API origin, clarify the target before writing integration code.
> Pages under /docs/beta/ document Beta; other product pages document Stable. Keep the CLI package, commands, API origin, and credentials within the selected version. State the documentation version in your answer.
> For MCP search, always pass version: Stable or version: Beta. Unfiltered search mixes both versions. For filesystem reads, keep Beta queries under /beta/ and exclude /beta/ from Stable queries; discover paths before reading them.
> The public docs base is https://photon.codes/docs. Convert MCP page paths to public URLs under that base, preserving /beta/ when present. Read https://photon.codes/docs/skill.md for version selection and https://photon.codes/docs/llms.txt for the version indexes.

# Create project

> Create project: createProject in the TypeScript, Python and Rust clients.

`POST /v1/organizations/{organizationId}/projects`

Creates in the authorized organization. In addition to account credentials, explicitly granted Service Identity API keys and M2M tokens may create projects. Project API keys cannot create projects. Creator and private credential evidence come only from the trusted authorization context. The caller-selected slug is immutable, must be 3 to 63 lowercase ASCII alphanumerics separated by single hyphens, and cannot be reserved or held by any active or deleted project.

<Tabs>
  <Tab title="TypeScript">
    ```typescript TypeScript theme={null}
    photon.organizations.projects.create(input: CreateProjectInput, options?: RequestOptions): Promise<CreateProjectOutput>
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    photon.organizations.projects.create(input: CreateProjectInput) -> models.Project
    ```
  </Tab>

  <Tab title="Rust">
    ```rust Rust theme={null}
    client.create_project(idempotency_key: String, organization_id: String, body: &types::CreateProjectRequest).await -> Result<ResponseValue<CreateProjectResponse>, Error<CreateProjectError>>
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```typescript TypeScript theme={null}
  import { Photon } from "@photon-ai/api";

  const photon = new Photon({
    headers: { Authorization: `Bearer ${process.env.PHOTON_API_TOKEN}` },
  });
  const result = await photon.organizations.projects.create({
    path: {
      organizationId: "organizationId",
    },
    headers: {
      idempotencyKey: "idempotencyKey",
    },
    body: {
      name: "name",
      slug: "slug",
    },
  });
  ```

  ```python Python theme={null}
  import os

  from photon_api import Photon
  from photon_api.rpc_generated import CreateProjectInput

  photon = Photon(headers={"Authorization": f"Bearer {os.environ['PHOTON_API_TOKEN']}"})
  result = photon.organizations.projects.create(
      CreateProjectInput.model_validate({
          "path": {
              "organizationId": "organizationId",
          },
          "headers": {
              "Idempotency-Key": "idempotencyKey",
          },
          "body": {
              "name": "name",
              "slug": "slug",
          },
      })
  )
  ```

  ```rust Rust theme={null}
  use photon_ai_api::{Credential, PhotonClientBuilder, SecretString};

  let token = std::env::var("PHOTON_API_TOKEN")?;
  let client = PhotonClientBuilder::new()
      .credential("accountServiceKey", Credential::Bearer(SecretString::from(token)))
      .build()?;
  let result = client
      .create_project(
          "idempotencyKey".to_owned(),
          "organizationId".to_owned(),
          &serde_json::from_value(serde_json::json!({
              "name": "name",
              "slug": "slug",
          }))?,
      )
      .await
      .map_err(|error| format!("{error:?}"))?
      .into_inner();
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "agentProfile": {
      "avatarUrl": "https://example.com",
      "firstName": "string",
      "lastName": null
    },
    "billingInitialization": "pending",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "createdByAccountId": null,
    "createdByActorId": null,
    "createdByActorKind": null,
    "deletedAt": null,
    "name": "string",
    "organizationId": "string",
    "projectId": "string",
    "slug": "string",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  }
  ```

  ```json 202 theme={null}
  {
    "agentProfile": {
      "avatarUrl": "https://example.com",
      "firstName": "string",
      "lastName": null
    },
    "billingInitialization": "pending",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "createdByAccountId": null,
    "createdByActorId": null,
    "createdByActorKind": null,
    "deletedAt": null,
    "name": "string",
    "organizationId": "string",
    "projectId": "string",
    "slug": "string",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  }
  ```
</ResponseExample>

## Parameters

<ParamField header="Idempotency-Key" type={"string"} required>
  Identifies one logical mutation across retries.
</ParamField>

<ParamField path="organizationId" type={"string"} required />

## Body

<ParamField body="name" type={"string"} required />

<ParamField body="slug" type={"string"} required />

## Returns

**`201`** The created project, ready to use: its billingInitialization is completed or unknown. A replay after setup finished answers here too. Project

<ResponseField name="agentProfile" type={"AgentProfile"} required />

<ResponseField name="billingInitialization" type={"ProjectBillingInitialization"} />

<ResponseField name="createdAt" type={"string (date-time)"} required />

<ResponseField name="createdByAccountId" type={"string | null"} required />

<ResponseField name="createdByActorId" type={"string | null"} required />

<ResponseField name="createdByActorKind" type={"ProjectCreatedByActorKind | null"} required />

<ResponseField name="deletedAt" type={"string (date-time) | null"} required />

<ResponseField name="name" type={"string"} required />

<ResponseField name="organizationId" type={"string"} required />

<ResponseField name="projectId" type={"string"} required />

<ResponseField name="slug" type={"string"} required />

<ResponseField name="updatedAt" type={"string (date-time)"} required />

**`202`** The project is created but its billing is still being set up. GET the Location after the Retry-After interval until billingInitialization is completed or unknown; retry\_required means setup is being retried, so keep polling. Project

Headers: `Location`. The raw response carries these headers; see [Raw responses](/docs/beta/api-client/raw-responses).

<ResponseField name="agentProfile" type={"AgentProfile"} required />

<ResponseField name="billingInitialization" type={"ProjectBillingInitialization"} />

<ResponseField name="createdAt" type={"string (date-time)"} required />

<ResponseField name="createdByAccountId" type={"string | null"} required />

<ResponseField name="createdByActorId" type={"string | null"} required />

<ResponseField name="createdByActorKind" type={"ProjectCreatedByActorKind | null"} required />

<ResponseField name="deletedAt" type={"string (date-time) | null"} required />

<ResponseField name="name" type={"string"} required />

<ResponseField name="organizationId" type={"string"} required />

<ResponseField name="projectId" type={"string"} required />

<ResponseField name="slug" type={"string"} required />

<ResponseField name="updatedAt" type={"string (date-time)"} required />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.