# Join Shared Thread

Records that the caller has **joined** the live-shared conversation behind a share link, so it becomes a first-class, **persistent entry in their thread list** (`GET /v1/threads`) that they can return to across reloads and keep co-working in — without owning it.

Unlike [Import Shared Thread](/api-reference/shared-threads/import-shared-thread), which makes a separate copy, joining keeps the caller on the **same underlying thread** so everyone co-works together in real time.

The operation is **idempotent**: re-joining returns the same join (no duplicate). It is allowed **only when the link's `access_level` is `live`** — a `view` or `fork` slug returns `403`. The caller must also pass the same resolution gates as opening the link (active member of the thread's organization; explicit grant for `explicit` links; not revoked or expired); an unknown or unauthorized link returns `404`.

A joined thread **auto-drops** from the caller's list once the underlying live link is revoked or expired — no explicit cleanup is needed.

The **owner** of the shared thread is an exception: joining their own link returns the thread as normal, but records nothing. The thread is already theirs, so it stays an owned entry in their list and is never reported as joined.

## Authentication

Requires **user** authentication (Bearer token). API-key authentication is rejected with `403`.

## Path Parameters

**`slug`** string required

The share-link slug, taken from the share URL. The link must be a `live` link.

## Body Parameters

None. The request takes no body.

## Returns

Returns the underlying thread as a `ThreadResponse` object (read-only metadata) with two fields set for the joiner:

- **is_joined** `boolean` — `true` (the caller joined this thread via a live link; they do not own it).
- **joined_via_slug** `string` — the slug to use for this thread's slug-scoped loads: [Get Shared Thread Messages](/api-reference/shared-threads/get-shared-thread-messages) and [Live Shared Thread](/api-reference/shared-threads/live-shared-thread).


The same row appears in subsequent `GET /v1/threads` responses with these fields set, so the client routes its message and live loads through the slug-scoped recipient endpoints.

## Code Examples

### cURL


```bash
curl -X POST https://api.aitronos.com/v1/shared-threads/abc123slug/join \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Python SDK


```python
from aitronos import Aitronos

client = Aitronos(api_key="", token="YOUR_TOKEN")
thread = client.threads.shared.join(slug="abc123slug")
print(thread.is_joined, thread.joined_via_slug)
```

### Python (requests)


```python
import requests

response = requests.post(
    "https://api.aitronos.com/v1/shared-threads/abc123slug/join",
    headers={"Authorization": "Bearer YOUR_TOKEN"},
)
print(response.json()["joined_via_slug"])
```

### JavaScript


```javascript
const response = await fetch(
  "https://api.aitronos.com/v1/shared-threads/abc123slug/join",
  {
    method: "POST",
    headers: { Authorization: "Bearer YOUR_TOKEN" },
  },
);
const thread = await response.json();
console.log(thread.is_joined, thread.joined_via_slug);
```

## Response Examples

### Success (201)


```json
{
  "id": "thread_9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a",
  "object": "thread",
  "title": "Q3 launch plan",
  "status": "inactive",
  "organization_id": "org_9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d",
  "message_count": 12,
  "is_shared": true,
  "share_count": 1,
  "live_share_count": 1,
  "is_joined": true,
  "joined_via_slug": "abc123slug",
  "created_at": "2026-06-28T09:40:00Z",
  "updated_at": "2026-06-28T09:40:00Z",
  "last_message_at": "2026-06-28T09:39:00Z"
}
```

### Error — Not a live link (403)


```json
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_PERMISSIONS",
    "message": "You do not have permission to perform this action.",
    "system_message": "This share link does not grant live co-working access",
    "type": "authorization_error",
    "status": 403,
    "details": {
      "link_id": "tslnk_2b1c3d4e5f6a7b8c9d0e1f2a3b4c5d6e",
      "access_level": "view"
    },
    "trace_id": "...",
    "timestamp": "..."
  }
}
```

### Error — Link not found or not authorized (404)

A caller the link was given to is told why instead: `details.unavailable_reason` is `thread_deleted` (404), `share_revoked` or `share_expired` (422), or `org_access_lost` (404), with the owner and sharer. See [When a link stops working](/api-reference/shared-threads/get-shared-thread#when-a-link-stops-working). Everyone else gets this uniform body.


```json
{
  "success": false,
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "The requested resource could not be found.",
    "system_message": "Share link not found",
    "type": "client_error",
    "status": 404,
    "details": {},
    "trace_id": "...",
    "timestamp": "..."
  }
}
```

## Related Resources

- [Leave Shared Thread](/api-reference/shared-threads/leave-shared-thread) — Remove the persistent joined entry
- [Get Shared Thread](/api-reference/shared-threads/get-shared-thread) — Open the share link
- [Get Shared Thread Messages](/api-reference/shared-threads/get-shared-thread-messages) — Read the joined thread's messages (slug-scoped)
- [Live Shared Thread](/api-reference/shared-threads/live-shared-thread) — Join the real-time co-working stream
- [Send to Shared Thread](/api-reference/shared-threads/send-shared-thread) — Post a message to the live-shared thread
- [Shared Thread Presence](/api-reference/shared-threads/shared-thread-presence) — Heartbeat presence as a joiner