# Open a conversation

POST

/v1/conversations

```sh
curl --request POST \
  --url https://example.com/v1/conversations \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{ "agentId": "example", "agentVersion": "example", "title": "example", "projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "scope": {}, "participantId": "example", "metadata": {} }'
```

Pins `(agentId, agentVersion)` at open time. `title` defaults to `"Untitled conversation"` when omitted; `projectId` puts it in a project, which must reach the agent (lists filter by it; omitted, the agent’s own project, as for a run, or the Default project for an agent filed under none); `scope` accepts arbitrary JSON.

## Authorizations

- **[bearerAuth](https://docs.kindgi.com/v0.1.10/reference/api.md#bearerauth)**

## Parameters

### Header Parameters

**Idempotency-Key**

string

\>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per `docs/API-ROUTE-CONVENTIONS.md` §3.1). A retry sent while the first request still runs is answered `409 idempotency-key-in-flight` with `Retry-After`, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets `409 idempotency-key-replay-withheld`, with the first request’s status and when it succeeded (from 0.1.5).

## Request Bodyrequired

application/json

object

**agentId**

required

AgentId.

string

\>= 1 characters

**agentVersion**

required

Semver — pinned at open time.

string

\>= 1 characters

**title**

Optional. Defaults to `"Untitled conversation"` when omitted.

string

**projectId**

The project the conversation is in; `GET /v1/conversations?scopeKind=project&scopeId=…` lists it. A project of the caller’s tenant, else `400 bad-input`, that reaches the agent, else `400 reference-out-of-scope`. Omitted: the agent’s own project, as for a run (the tenant’s Default project for an agent filed under none).

string format: uuid

**scope**

Structural scope (project id, matter id, etc.). Treated opaquely by the runtime.

object

**_key_**

additional properties

any

**participantId**

string

**metadata**

object

**_key_**

additional properties

any

##### Examplegenerated

```json
{
  "agentId": "example",
  "agentVersion": "example",
  "title": "example",
  "projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
  "scope": {},
  "participantId": "example",
  "metadata": {}
}
```

## Responses

### 201

Conversation opened.

application/json

object

**id**

required

ConversationId.

string format: uuid

**tenantId**

required

string format: uuid

**agentId**

required

string

**agentVersion**

required

Semver.

string

**title**

required

string

**participantId**

string

**projectId**

The project the conversation is in: the project of the run that opened it, or `projectId` on open (when omitted, the agent’s own project, or the tenant’s Default project for an agent filed under none). Absent on conversations from before Kindgi 0.1.3; those are listed only without a scope.

string format: uuid

**openedBy**

Who opened it: the caller’s principal (`user:<id>`, `service_account:<id>`), or, for one a turn opened, whoever the run acts for. Set by the server, never from a request’s body. Absent on conversations an older runtime opened, and when the caller had no principal; those aren’t listed by `?openedBy=me`.

string

**scope**

required

Free-form scope object (currently `{ tenantId }` in tests; enterprises extend with `matterId`, `engagementId`, etc.).

object

**_key_**

additional properties

any

**status**

required

Lifecycle status derived from `closedAt`: `open` when null, `closed` otherwise.

string

Allowed values: open closed

**openedAt**

required

string format: date-time

**closedAt**

string format: date-time

**unregisteredAt**

When it was unregistered (`POST /v1/conversations/{conversationId}/unregister`). Only the unregister call returns it: reads no longer do.

string format: date-time

**turnCount**

required

integer

**lastMessageAt**

string format: date-time

**metadata**

object

**_key_**

additional properties

any

##### Example

```json
{
  "status": "open"
}
```

### 400

Malformed request body, or `projectId` names no project of this tenant. Or `reference-out-of-scope`: the agent isn’t registered in the conversation’s project, its org or the tenant, or `agentVersion` isn’t a version that project runs, such as one made in an earlier environment and not yet promoted (`details.issues`, at `/agentId`, whose message names the version). Nothing is opened.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 401

Missing / malformed / expired / revoked bearer token.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 403

No `execute` on the agent, or, for an agent more than one project serves opened in one of its projects, no `call` there (`caller` or `editor`); or, otherwise, naming a `projectId` without `write` on it (its turns land there, as a run naming one does); or a `participantId` whose memory the caller may not read (`participant-not-allowed`): its turns run with that participant’s memory, so opening it for someone takes being them (a person, by their user id) or `write` on its project. The rights on the agent and on a named project are checked before `projectId` is looked up, so they answer the same whether or not it names a project.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 409

Idempotency-Key was reused with a different body, or resource-state conflict.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 413

The request body is over the API’s limit (`request-too-large`; `details.maxBytes` says how much).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 500

Server error (unmapped domain code or framework crash).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

## See also

- [`GET /v1/conversations`: List conversations](https://docs.kindgi.com/v0.1.10/reference/api/operations/conversationslist.md)
- [Hold a conversation](https://docs.kindgi.com/v0.1.10/guides/agents/conversations.md)
- [Error code `participant-not-allowed`](https://docs.kindgi.com/v0.1.10/reference/errors.md#participant-not-allowed)
- [Error code `reference-out-of-scope`](https://docs.kindgi.com/v0.1.10/reference/errors.md#reference-out-of-scope)
- [Error code `request-too-large`](https://docs.kindgi.com/v0.1.10/reference/errors.md#request-too-large)
- [Every error code](https://docs.kindgi.com/v0.1.10/reference/errors.md)
