> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.v2.rasen.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.v2.rasen.ai/_mcp/server.

# List knowledge sources

GET https://api.v2.rasen.ai/v1/knowledge/sources

List source metadata. Defaults to owner_type=workspace. owner_type=agent selects agent-owned sources; owner_agent_id then narrows owners. attached_agent_id is a separate any-selected-agent filter. All filters are ANDed. Ownership is not a permission; access follows the key capabilities. ID-list filters use repeated query names. Raw supplied ID count across fields is at most 100. Cursor binds normalized filters; filtered lists are not exact batch retrieval.

Reference: https://docs.v2.rasen.ai/api-reference/knowledge-sources/list

## Authentication

- `Authorization` header (bearer token, required) — Create and manage workspace-owned keys through the existing app session routes, outside this public API. Creator and manager identities are audit actors only. Key validity follows workspace policy, expiry and explicit revocation, independently of creator membership. Do not include a workspace-selection header.

## Request

### Query parameters

- `limit` (integer, optional, default: 50) — Page size; 50 by default, at most 200.
- `cursor` (string, optional) — Opaque cursor bound to the workspace, every filter, grouping and limit. Send them unchanged with it. Expires after 24 hours.
- `source_id` (list of string, optional) — Repeat the query name for multiple IDs. OR within this field; AND across fields. Maximum 100 raw ID entries total across all ID filters. Blank values are invalid. Unknown/inaccessible IDs produce no rows, not an existence disclosure. An empty array is invalid and refused: SDKs refuse it before sending, and the server refuses an empty or blank value. Omission means no filter.
- `owner_agent_id` (list of string, optional) — Repeat the query name for multiple IDs. OR within this field; AND across fields. Maximum 100 raw ID entries total across all ID filters. Blank values are invalid. Unknown/inaccessible IDs produce no rows, not an existence disclosure. An empty array is invalid and refused: SDKs refuse it before sending, and the server refuses an empty or blank value. Omission means no filter.
- `attached_agent_id` (list of string, optional) — Repeat the query name for multiple IDs. OR within this field; AND across fields. Maximum 100 raw ID entries total across all ID filters. Blank values are invalid. Unknown/inaccessible IDs produce no rows, not an existence disclosure. An empty array is invalid and refused: SDKs refuse it before sending, and the server refuses an empty or blank value. Omission means no filter.
- `owner_type` (enum, optional, default: workspace) — owner_agent_id requires owner_type=agent.
  - Allowed values: `workspace`, `agent`
- `state` (list of enum, optional) — Omitted excludes archived sources. Repeat for OR within this field; AND with other fields. These are not ID entries; at most 16 values per field, the same bound as the POST form. An empty array is invalid and refused: SDKs refuse it before sending, and the server refuses an empty or blank value. Omission means no filter.
  - Allowed values: `pending`, `ingesting`, `ready`, `fallback`, `failed`, `archived`
- `resource_key` (list of string, optional) — Exact resource-key lookup. Repeat the name for several keys (OR). Each key matches zero or one resource of this type. A resource_key filter ignores the default owner and archive scoping of this list: it returns the resource in any owner and any state, so reconciliation never misses an existing resource. Counts toward the 100 raw filter values per request. Unknown keys yield no rows. An empty array is invalid and refused: SDKs refuse it before sending, and the server refuses an empty or blank value. Omission means no filter.

## Response

### 200

List knowledge sources.

- `items` (list of KnowledgeSource, required)
- `next_cursor` (string, required, nullable) — Opaque continuation cursor. Null means the last page.

## Errors

### 400 Bad Request Error

Invalid input or cursor. Correct the request.

- `error` (ErrorResponseError, required) — Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

### 401 Unauthorized Error

Invalid, expired or revoked API key. Creator departure or membership changes do not invalidate a workspace key.

- `error` (ErrorResponseError, required) — Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

### 403 Forbidden Error

Operation not allowed by current credential or workspace access.

- `error` (ErrorResponseError, required) — Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

### 429 Too Many Requests Error

Rate limited. Respect Retry-After and retry the same intent where permitted.

- `error` (ErrorResponseError, required) — Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

### 500 Internal Server Error

Internal error. The effect may have happened. Retry the same request with the same Idempotency-Key; read the resource before creating a new intent. For an operation that takes an Idempotency-Key, a client retry with the same key is safe: the server replays the stored outcome if the first attempt took effect; if the first attempt had no effect, the retry performs the operation once. Never retry with a new key.

- `error` (ErrorResponseError, required) — Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

### 503 Service Unavailable Error

Service unavailable. Respect Retry-After where present. For an operation that takes an Idempotency-Key, a client retry with the same key is safe: the server replays the stored outcome if the first attempt took effect; if the first attempt had no effect, the retry performs the operation once. Never retry with a new key.

- `error` (ErrorResponseError, required) — Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

## Types

### KnowledgeSource

Fallback means available as bounded prompt context when the source is in the direct agent library; it is not indexed retrieval. Reads do not start ingestion. content\_sha256 describes ingested source bytes, not necessarily the local input file after extraction. A URL source is refreshed by reingest and keeps its key. File and text content is immutable: for new content create a new source with a new name and a versioned key such as "\<key>:v2", add it to each required agent library, publish those agents, then archive the old source. Names and keys stay taken by archived sources; deleting a source that no snapshot or published version has cited frees them; a duplicate name returns conflict (details.reason=name\_taken). Keep old source revisions while publications refer to them. A URL reingest refreshes its source revision. Agent retirement is not available through this API. owner is immutable. Agent ownership controls library membership and lifecycle; it is not a permission. Access follows the key capabilities. Shared attachment does not transfer ownership. name is unique within its owner scope (the workspace library, or one agent library), so two agents can each own a same-named document.

- `id` (string, required) — Opaque kb identifier. Do not parse its contents.
- `name` (string, required)
- `kind` (string, required) — Open response vocabulary. Preserve unknown values; never assume they mean success.
- `state` (string, required) — pending and ingesting are in progress: keep polling. Settled states: ready (retrieval-ready), fallback (text could not be indexed but can be frozen as bounded prompt context when the source is in an agent library), failed (read failure), archived (hidden from new library selection; retained published evidence keeps working). Open response vocabulary. Preserve unknown values; never assume they mean success.
- `revision` (string, required)
- `created_at` (datetime, required)
- `failure` (string, required, nullable) — Safe registered reason.
- `content_sha256` (string, required, nullable)
- `content_bytes` (integer, required, nullable)
- `media_type` (string, required, nullable)
- `ingested_at` (datetime, required, nullable)
- `updated_at` (datetime, required)
- `owner` (SourceOwnerRead, required)
- `resource_key` (string, required, nullable) — Optional caller-chosen resource key: an opaque external identifier that matches your own record (for example a CRM ID, a configuration-file ID or a UUID) to this resource. Rasen still generates the canonical id; use id in paths and references. Case-sensitive, compared exactly, never normalized or parsed. 1-128 characters from A-Z a-z 0-9 . _ : ~ - and starting with a letter or digit; UUIDs and ULIDs are valid. Unique per resource type within one workspace; separate environment workspaces can reuse the same key. Set only at creation and immutable afterwards. A create with a key that already exists returns 409 resource_key_conflict with details.existing_id; it never updates or returns the existing resource. Not an Idempotency-Key: that header identifies one request intent for 24 hours, and a same-intent replay returns its original receipt before the resource-key check runs. Uniqueness includes archived resources. A key becomes free again only after its resource is permanently deleted or erased (a deleted secret or a deleted knowledge source); archive never frees it.
- `poll_after_seconds` (integer, required, nullable) — Seconds to wait before the next read while state is pending or ingesting. Null when the state is settled.

### ErrorResponseError

Only code and message are required. Rasen sends details, request_id and retry on every error, but clients must parse an error that lacks them, so a typed error is never lost to a parsing failure.

- `code` (string, required) — Stable code. Branch on code (and details.reason for conflict), never on message. Each code has one HTTP status; see components.x-error-catalog.
- `message` (string, required) — Safe description; no provider payload or submitted secrets.
- `details` (map from string to any, optional) — Safe code-specific details. The public fields for each code are listed in components.x-error-catalog. Details never contain a request fingerprint, a hash of a request, secret material or another tenant's data. forbidden may include required_capabilities (a list).
- `request_id` (string, optional) — Same value as the X-Request-Id header. Quote it to support.
- `retry` (string, optional) — Retry class of this code: no (fix the request or state first), yes (retry the same request and the same Idempotency-Key), retry_after (wait for Retry-After, then retry the same request). Open response vocabulary. Preserve unknown values; never assume they mean success.

### SourceOwnerRead

- `type`: `workspace` (workspace)
- `type`: `agent` (agent)
  - `agent_id` (string, required) — Opaque agent identifier. Do not parse its contents.

## Examples

**Response**

```json
{
  "items": [
    {
      "id": "kb_01j00000000000000000000000",
      "name": "example",
      "kind": "url",
      "state": "pending",
      "revision": "example",
      "created_at": "2026-09-25T10:00:00Z",
      "failure": null,
      "content_sha256": "example",
      "content_bytes": 0,
      "media_type": "example",
      "ingested_at": "2026-09-25T10:02:00Z",
      "updated_at": "2026-09-25T10:06:00Z",
      "owner": {
        "type": "workspace"
      },
      "resource_key": "3f8e5a0c-9d1b-4c7e-a2f4-6b0d9e1c7a55",
      "poll_after_seconds": 1
    }
  ],
  "next_cursor": "eyJwYWdlIjoyfQ"
}
```

**SDK Code**

```python knowledgeSources_list_example
import requests

url = "https://api.v2.rasen.ai/v1/knowledge/sources"

headers = {"Authorization": "Bearer <api_key>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript knowledgeSources_list_example
const url = 'https://api.v2.rasen.ai/v1/knowledge/sources';
const options = {method: 'GET', headers: {Authorization: 'Bearer <api_key>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```ruby knowledgeSources_list_example
require 'uri'
require 'net/http'

url = URI("https://api.v2.rasen.ai/v1/knowledge/sources")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <api_key>'

response = http.request(request)
puts response.read_body
```

```java knowledgeSources_list_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.v2.rasen.ai/v1/knowledge/sources")
  .header("Authorization", "Bearer <api_key>")
  .asString();
```

```php knowledgeSources_list_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.v2.rasen.ai/v1/knowledge/sources', [
  'headers' => [
    'Authorization' => 'Bearer <api_key>',
  ],
]);

echo $response->getBody();
```

```csharp knowledgeSources_list_example
using RestSharp;

var client = new RestClient("https://api.v2.rasen.ai/v1/knowledge/sources");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <api_key>");
IRestResponse response = client.Execute(request);
```

```swift knowledgeSources_list_example
import Foundation

let headers = ["Authorization": "Bearer <api_key>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.v2.rasen.ai/v1/knowledge/sources")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```