> ## 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 or get a User

> Create or get a User: createOrGetUser in the TypeScript, Python, Rust and Go clients.

`POST /v1/projects/{id}/users`

Creates or reconciles a User by normalized handle. WhatsApp and iMessage phone classification uses line allocation and project ownership; New iMessage email handles start as Human without lookup; existing email identities retain their producer-observed classification and ownership. WhatsApp Business uses project ownership. These three platforms perform no provider profile or enrichment fetch. Shared Agents expose type=shared without ownership IDs; dedicated Agents expose resourceId for this project or pairwise managedBy for another project. Dedicated lines without an active owner are unavailable. SMS retains its existing ownership and phone number enrichment behavior. Email retains domain ownership resolution, lowercase ASCII domains and case-preserved local parts. Dependency failures fail before classification writes. The natural identity is the project path ID, platform, and handle. Retrying after a committed creation whose response was lost returns the same User with 200 rather than replaying 201.

**TypeScript**

```typescript TypeScript theme={null}
photon.projects.createOrGetUser(input: CreateOrGetUserInput, options?: RequestOptions): Promise<CreateOrGetUserOutput>
```

**Python**

```python Python theme={null}
photon.projects.create_or_get_user(input: CreateOrGetUserInput) -> models.PlatformUser
```

**Rust**

```rust Rust theme={null}
client.create_or_get_user(id: String, body: &types::CreateOrGetUserRequest).await -> Result<ResponseValue<CreateOrGetUserResponse>, Error<CreateOrGetUserError>>
```

**Go**

```go Go theme={null}
client.Projects.CreateOrGetUser(ctx context.Context, params *CreateOrGetUserParams, opts ...RequestOption) (*PlatformUser, error)
```

```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.projects.createOrGetUser({
  path: {
    id: "id",
  },
  body: {
    handle: "handle",
    platform: "sms",
  },
});
```

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

from photon_api import Photon
from photon_api.rpc_generated import CreateOrGetUserInput

photon = Photon(headers={"Authorization": f"Bearer {os.environ['PHOTON_API_TOKEN']}"})
result = photon.projects.create_or_get_user(
    CreateOrGetUserInput.model_validate({
        "path": {
            "id": "id",
        },
        "body": {
            "handle": "handle",
            "platform": "sms",
        },
    })
)
```

```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_or_get_user(
        "id".to_owned(),
        &serde_json::from_value(serde_json::json!({
            "handle": "handle",
            "platform": "sms",
        }))?,
    )
    .await
    .map_err(|error| format!("{error:?}"))?
    .into_inner();
```

```go Go theme={null}
import (
	"context"
	"encoding/json"
	"os"

	photonapi "github.com/photon-hq/api/packages/go"
)

ctx := context.Background()
client := photonapi.NewClient(photonapi.WithAPIKey(os.Getenv("PHOTON_API_TOKEN")))
var body photonapi.CreateOrGetUserRequest
if err := json.Unmarshal([]byte(`{
	"handle": "handle",
	"platform": "sms"
}`), &body); err != nil {
	return err
}
result, err := client.Projects.CreateOrGetUser(ctx, &photonapi.CreateOrGetUserParams{
	ID: "id",
	Body: body,
})
if err != nil {
	return err
}
_ = result
```

```json 200 theme={null}
{
  "createdAt": "2026-01-01T00:00:00.000Z",
  "details": {
    "resourceId": "pho_res_00000000000000000000000001",
    "type": "dedicated"
  },
  "handle": "+14155550123",
  "id": "pho_usr_00000000000000000000000001",
  "kind": "agent",
  "metadata": {},
  "platform": "whatsapp",
  "projectId": "pho_prj_00000000000000000000000001",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}
```

```json 201 theme={null}
{
  "createdAt": "2026-01-01T00:00:00.000Z",
  "details": {
    "resourceId": "pho_res_00000000000000000000000001",
    "type": "dedicated"
  },
  "handle": "+14155550123",
  "id": "pho_usr_00000000000000000000000001",
  "kind": "agent",
  "metadata": {},
  "platform": "whatsapp",
  "projectId": "pho_prj_00000000000000000000000001",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}
```

## Parameters

**id** `string` *required*

## Body

**handle** `string` *required*

**platform** `Platform` *required*

## Returns

**`200`** The existing User after authoritative classification and any required repair. PlatformUser

**createdAt** `string (date-time)` *required*

When Photon first persisted this resource.

**details** `TelegramUserDetails` *required*

**handle** `string` *required*

**id** `string` *required*

**kind** `string` *required*

**metadata** `ResourceMetadata` *required*

**platform** `Platform` *required*

**projectId** `string` *required*

**updatedAt** `string (date-time)` *required*

When Photon last persisted a change to this resource's public state.

**`201`** The User was created from the platform’s resolved identity and authoritative observations. PlatformUser

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

**createdAt** `string (date-time)` *required*

When Photon first persisted this resource.

**details** `TelegramUserDetails` *required*

**handle** `string` *required*

**id** `string` *required*

**kind** `string` *required*

**metadata** `ResourceMetadata` *required*

**platform** `Platform` *required*

**projectId** `string` *required*

**updatedAt** `string (date-time)` *required*

When Photon last persisted a change to this resource's public state.


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