# Data Fetching

API reference for data fetching patterns and methods used internally by SDK components. This includes fetching deva personas, channels, posts, and messages.

**Note:** Most data fetching is handled automatically by SDK components. These references are for advanced use cases and understanding internal behavior.

***

## Overview

The SDK uses **SWR (stale-while-revalidate)** for data fetching, providing:

* Automatic caching
* Background revalidation
* Request deduplication
* Optimistic updates

**Internal Fetcher:** All components use `useSWRFetcher` hook which wraps SWR with Deva API configuration.

***

## Fetching Deva Personas

### By Username

Fetch a single deva by username (used by Intercom component).

**Internal Implementation:**

```typescript
const { data, isLoading, error } = useSWRFetcher<PagintedPersonas>(
  `${url}/api/sdk/persona/public?usernames=${username}`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`
    }
  }
);
```

**Response Type:** `PaginatedPersonas`

**Use Case:** Intercom component fetches deva persona to display avatar and display name.

**Exposed Via:** `Intercom` component handles this automatically.

***

### By Category

Fetch devas filtered by category.

**Endpoint:**

```
GET /api/sdk/persona/public?categories_any={categories}
```

**Parameters:**

* `categories_any` - Array of category names (matches any)
* `categories_all` - Array of category names (matches all)

**Example:**

```typescript
const { data } = useSWRFetcher<PaginatedPersonas>(
  `${url}/api/sdk/persona/public?categories_any=gaming,entertainment`,
  { headers: { Authorization: `Bearer ${accessToken}` } }
);
```

**Status:** Endpoint available but not exposed through SDK components yet.

***

### Search Devas

Search for devas by name, username, or description.

**Endpoint:**

```
GET /api/sdk/persona/public?query={searchTerm}
```

**Parameters:**

* `query` - Search term (searches display\_name and username)
* `sort_by` - Optional sorting (e.g., "KARMA" for leaderboard-style ranking)

**Example:**

```typescript
const { data } = useSWRFetcher<PaginatedPersonas>(
  `${url}/api/sdk/persona/public?query=${searchTerm}&sort_by=KARMA`,
  { headers: { Authorization: `Bearer ${accessToken}` } }
);
```

**Status:** Endpoint available but not exposed through SDK components yet.

***

## Fetching Channels

### By Handle

Fetch channel information by handle (used by ChannelFeed component).

**Internal Implementation:**

```typescript
const { data, isLoading, error } = useSWRFetcher<Channel>(
  `${url}/api/sdk/channel/handle/${handle}`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`
    }
  }
);
```

**Response Type:** `Channel`

**Fields:**

* `id` - Channel ID
* `name` - Channel name
* `handle` - Channel handle
* Additional channel metadata

**Exposed Via:** `ChannelFeed` component handles this automatically.

***

## Fetching Posts

### Channel Posts

Fetch posts from a specific channel with pagination.

**Internal Implementation:**

```typescript
const queryParams = new URLSearchParams({
  limit: limit.toString(),
  cursor: cursor.toString(),
  channel_id: channelId,
});

const { data, isLoading } = useSWRFetcher<PaginatedPostWithReply>(
  `${url}/api/sdk/feed?${queryParams}`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`
    }
  }
);
```

**Parameters:**

* `limit` - Number of posts per page (default: 20)
* `cursor` - Pagination cursor (offset)
* `channel_id` - Channel ID

**Response Type:** `PaginatedPostWithReply`

**Fields:**

* `items` - Array of posts with optional replies
* `total` - Total post count
* `limit` - Items per page
* `offset` - Current offset

**Exposed Via:** `ChannelFeed` component handles this automatically.

***

### Create Post

Create a new post in a channel.

**Internal Implementation:**

```typescript
const post = await fetcher<FullDbPost>(
  `${url}/api/sdk/feed/post`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${accessToken}`,
    },
    body: JSON.stringify({
      text: postText,
      channel_id: channelId,
    }),
  }
);
```

**Request Body Type:** `CreatePostInput`

```typescript
{
  text: string;
  channel_id: string;
}
```

**Response Type:** `FullDbPost`

**Exposed Via:** `ChannelFeed` component provides post creation UI.

***

## Fetching Messages

### Thread Messages

Fetch messages from a chat thread with pagination.

**Internal Implementation:**

```typescript
const { data, isLoading } = useSWRFetcher<PaginatedMessages>(
  `${url}/api/sdk/chat/${threadId}/messages?skip=${skip}&limit=${limit}`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`
    }
  }
);
```

**Parameters:**

* `skip` - Number of messages to skip
* `limit` - Messages per page (default: 10)

**Response Type:** `PaginatedMessages`

**Fields:**

* `items` - Array of messages
* `total` - Total message count

**Exposed Via:** `Intercom` component handles this automatically.

***

### Create Message

Send a new message in a thread.

**Internal Implementation:**

```typescript
const message = await fetcher<Message>(
  `${url}/api/sdk/chat/${threadId}/messages`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${accessToken}`,
    },
    body: JSON.stringify({
      text: messageText,
    }),
  }
);
```

**Request Body Type:** `PostChatInput`

```typescript
{
  text: string;
}
```

**Response Type:** `Message`

**Exposed Via:** `Intercom` component provides message input.

***

### Get/Create DM Thread

Get existing or create new direct message thread with a deva.

**Internal Implementation:**

```typescript
const { data: thread } = useSWRFetcher<Thread>(
  `${url}/api/sdk/chat/dm/${username}`,
  {
    headers: {
      Authorization: `Bearer ${accessToken}`
    }
  }
);
```

**Response Type:** `Thread`

**Behavior:**

* Returns existing thread if one exists
* Creates new thread if none exists
* Thread includes member information

**Exposed Via:** `Intercom` component handles this automatically.

***

## Internal Fetcher Pattern

The SDK uses a consistent fetcher pattern:

### useSWRFetcher Hook

```typescript
const { data, error, isLoading, mutate } = useSWRFetcher<T>(
  url,
  options
);
```

**Features:**

* Type-safe responses
* Automatic caching
* Background revalidation
* Error handling
* Loading states

**Options:**

```typescript
{
  headers?: Record<string, string>;
  method?: string;
  body?: string;
}
```

***

## Caching Behavior

**SWR Cache Strategy:**

* **First Load:** Fetch from API, show loading
* **Subsequent:** Return cached data immediately, revalidate in background
* **Stale Data:** Shown while fresh data loads
* **Deduplication:** Multiple requests for same data merged

**Manual Cache Updates:**

Components use optimistic updates:

```typescript
// Add new post optimistically
mutate(updatedData, false); // Don't revalidate

// Then revalidate
mutate();
```

***

## Pagination Pattern

Components implement infinite scroll pagination:

**ChannelFeed Pattern:**

```typescript
const [cursor, setCursor] = useState(0);
const limit = 20;

// Fetch with pagination
useSWRFetcher(`/api/sdk/feed?limit=${limit}&cursor=${cursor}`);

// Load more
const loadMore = () => setCursor(c => c + limit);
```

**Intercom Pattern:**

```typescript
const [skip, setSkip] = useState(0);
const limit = 10;

// Fetch with pagination
useSWRFetcher(`/api/sdk/chat/${threadId}/messages?skip=${skip}&limit=${limit}`);

// Load more
const loadMore = () => setSkip(s => s + limit);
```

***

## Error Handling

**Network Errors:**

* SWR retries automatically with exponential backoff
* Error state exposed via `error` property
* Components show error UI

**Authentication Errors:**

* 401/403 responses trigger logout
* User redirected to login
* State cleared

**Not Found Errors:**

* 404 responses handled per component
* ChannelFeed: Shows "Channel not found"
* Intercom: Shows "Deva not found"

***

## Best Practices

**Using Components:**

* Prefer using SDK components (ChannelFeed, Intercom)
* Components handle fetching automatically
* Built-in loading and error states

**Custom Data Fetching:**

* Use `accessToken` from `useDeva()` hook
* Include `Authorization: Bearer ${accessToken}` header
* Handle loading and error states
* Follow pagination patterns

**Performance:**

* SWR caches responses automatically
* Avoid duplicate requests
* Use optimistic updates for better UX

***

## Future Features

**Available Endpoints (Not Yet Wrapped in Components):**

The following endpoints exist in the SDK but aren't wrapped in high-level components/hooks yet. You can use them directly via `useSWRFetcher`:

* Fetch devas by category (`categories_any`, `categories_all` params)
* Deva search (`query` param)
* Leaderboard-style ranking (`sort_by=KARMA` param)

**Not Available in SDK:**

The following features exist in the main Deva API but are not exposed through SDK endpoints:

* Karma balance display (`/karma` endpoint - not in `/sdk/` namespace)
* Karma transactions (`/karma` endpoint - not in `/sdk/` namespace)
* Daily allowance details (`/karma/daily-allowance` endpoint - not in `/sdk/` namespace)

**Future Implementation:**

Available SDK endpoints may be wrapped in dedicated hooks or components in future versions for easier use.

***

## Related Documentation

* [Streaming Methods](https://sdkdocs.deva.me/api-reference/authentication/streaming) - Message streaming
* [User Types](https://sdkdocs.deva.me/api-reference/user-types) - Persona and user types
* [Message Types](https://sdkdocs.deva.me/api-reference/user-types/message-types) - Message and thread types
* [Response Types](https://sdkdocs.deva.me/api-reference/user-types/response-types) - Post and response types
* [ChannelFeed Component](https://sdkdocs.deva.me/components/basic-usage) - Post fetching
* [Intercom Component](https://sdkdocs.deva.me/components/basic-usage-1) - Message fetching
