curl --request POST \
--url https://app.pepline.ai/api/v1/knowledge_sources \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"body": "<string>",
"url": "<string>",
"max_pages": 30,
"filename": "<string>",
"data": "<string>",
"external_id": "<string>",
"language": "<string>",
"metadata": {},
"reading_brief": "<string>",
"agents": [
"<string>"
]
}
'import requests
url = "https://app.pepline.ai/api/v1/knowledge_sources"
payload = {
"title": "<string>",
"body": "<string>",
"url": "<string>",
"max_pages": 30,
"filename": "<string>",
"data": "<string>",
"external_id": "<string>",
"language": "<string>",
"metadata": {},
"reading_brief": "<string>",
"agents": ["<string>"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
body: JSON.stringify('<string>'),
url: '<string>',
max_pages: 30,
filename: '<string>',
data: '<string>',
external_id: '<string>',
language: '<string>',
metadata: {},
reading_brief: '<string>',
agents: ['<string>']
})
};
fetch('https://app.pepline.ai/api/v1/knowledge_sources', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.pepline.ai/api/v1/knowledge_sources",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'body' => '<string>',
'url' => '<string>',
'max_pages' => 30,
'filename' => '<string>',
'data' => '<string>',
'external_id' => '<string>',
'language' => '<string>',
'metadata' => [
],
'reading_brief' => '<string>',
'agents' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.pepline.ai/api/v1/knowledge_sources"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"body\": \"<string>\",\n \"url\": \"<string>\",\n \"max_pages\": 30,\n \"filename\": \"<string>\",\n \"data\": \"<string>\",\n \"external_id\": \"<string>\",\n \"language\": \"<string>\",\n \"metadata\": {},\n \"reading_brief\": \"<string>\",\n \"agents\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.pepline.ai/api/v1/knowledge_sources")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"body\": \"<string>\",\n \"url\": \"<string>\",\n \"max_pages\": 30,\n \"filename\": \"<string>\",\n \"data\": \"<string>\",\n \"external_id\": \"<string>\",\n \"language\": \"<string>\",\n \"metadata\": {},\n \"reading_brief\": \"<string>\",\n \"agents\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.pepline.ai/api/v1/knowledge_sources")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"body\": \"<string>\",\n \"url\": \"<string>\",\n \"max_pages\": 30,\n \"filename\": \"<string>\",\n \"data\": \"<string>\",\n \"external_id\": \"<string>\",\n \"language\": \"<string>\",\n \"metadata\": {},\n \"reading_brief\": \"<string>\",\n \"agents\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "knowledge_source",
"id": 123,
"kind": "text",
"title": "<string>",
"status": "ready",
"agents": [
"<string>"
],
"metadata": {},
"entries": {
"total": 123,
"ingested": 123,
"pending": 123,
"failed": 123
},
"archived": true,
"created_at": "2023-11-07T05:31:56Z",
"external_id": "<string>",
"url": "<string>",
"failure_reason": "<string>",
"language": "<string>",
"digest": "<string>",
"reading_brief": "<string>",
"refresh_every": "daily",
"next_refresh_at": "2023-11-07T05:31:56Z",
"max_pages": 123,
"last_update_at": "2023-11-07T05:31:56Z",
"body": "<string>"
}{
"object": "knowledge_source",
"id": 123,
"kind": "text",
"title": "<string>",
"status": "ready",
"agents": [
"<string>"
],
"metadata": {},
"entries": {
"total": 123,
"ingested": 123,
"pending": 123,
"failed": 123
},
"archived": true,
"created_at": "2023-11-07T05:31:56Z",
"external_id": "<string>",
"url": "<string>",
"failure_reason": "<string>",
"language": "<string>",
"digest": "<string>",
"reading_brief": "<string>",
"refresh_every": "daily",
"next_refresh_at": "2023-11-07T05:31:56Z",
"max_pages": 123,
"last_update_at": "2023-11-07T05:31:56Z",
"body": "<string>"
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}Create or upsert a knowledge source
One source per ORIGIN: a paste (text), a document (file), a single page (url), or a whole site (website — pages are kept as entries beneath one source). With external_id, this endpoint UPSERTS: 201 when a new source is created, 200 when the existing source with that external_id was updated (and refreshed if its content changed — an identical payload short-circuits without re-processing, so retries are free). Supply Idempotency-Key for byte-exact retry semantics on creates without external_id. Website sources are limited to 5 creations per hour per key.
curl --request POST \
--url https://app.pepline.ai/api/v1/knowledge_sources \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"body": "<string>",
"url": "<string>",
"max_pages": 30,
"filename": "<string>",
"data": "<string>",
"external_id": "<string>",
"language": "<string>",
"metadata": {},
"reading_brief": "<string>",
"agents": [
"<string>"
]
}
'import requests
url = "https://app.pepline.ai/api/v1/knowledge_sources"
payload = {
"title": "<string>",
"body": "<string>",
"url": "<string>",
"max_pages": 30,
"filename": "<string>",
"data": "<string>",
"external_id": "<string>",
"language": "<string>",
"metadata": {},
"reading_brief": "<string>",
"agents": ["<string>"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
body: JSON.stringify('<string>'),
url: '<string>',
max_pages: 30,
filename: '<string>',
data: '<string>',
external_id: '<string>',
language: '<string>',
metadata: {},
reading_brief: '<string>',
agents: ['<string>']
})
};
fetch('https://app.pepline.ai/api/v1/knowledge_sources', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.pepline.ai/api/v1/knowledge_sources",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'body' => '<string>',
'url' => '<string>',
'max_pages' => 30,
'filename' => '<string>',
'data' => '<string>',
'external_id' => '<string>',
'language' => '<string>',
'metadata' => [
],
'reading_brief' => '<string>',
'agents' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.pepline.ai/api/v1/knowledge_sources"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"body\": \"<string>\",\n \"url\": \"<string>\",\n \"max_pages\": 30,\n \"filename\": \"<string>\",\n \"data\": \"<string>\",\n \"external_id\": \"<string>\",\n \"language\": \"<string>\",\n \"metadata\": {},\n \"reading_brief\": \"<string>\",\n \"agents\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.pepline.ai/api/v1/knowledge_sources")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"body\": \"<string>\",\n \"url\": \"<string>\",\n \"max_pages\": 30,\n \"filename\": \"<string>\",\n \"data\": \"<string>\",\n \"external_id\": \"<string>\",\n \"language\": \"<string>\",\n \"metadata\": {},\n \"reading_brief\": \"<string>\",\n \"agents\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.pepline.ai/api/v1/knowledge_sources")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"body\": \"<string>\",\n \"url\": \"<string>\",\n \"max_pages\": 30,\n \"filename\": \"<string>\",\n \"data\": \"<string>\",\n \"external_id\": \"<string>\",\n \"language\": \"<string>\",\n \"metadata\": {},\n \"reading_brief\": \"<string>\",\n \"agents\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "knowledge_source",
"id": 123,
"kind": "text",
"title": "<string>",
"status": "ready",
"agents": [
"<string>"
],
"metadata": {},
"entries": {
"total": 123,
"ingested": 123,
"pending": 123,
"failed": 123
},
"archived": true,
"created_at": "2023-11-07T05:31:56Z",
"external_id": "<string>",
"url": "<string>",
"failure_reason": "<string>",
"language": "<string>",
"digest": "<string>",
"reading_brief": "<string>",
"refresh_every": "daily",
"next_refresh_at": "2023-11-07T05:31:56Z",
"max_pages": 123,
"last_update_at": "2023-11-07T05:31:56Z",
"body": "<string>"
}{
"object": "knowledge_source",
"id": 123,
"kind": "text",
"title": "<string>",
"status": "ready",
"agents": [
"<string>"
],
"metadata": {},
"entries": {
"total": 123,
"ingested": 123,
"pending": 123,
"failed": 123
},
"archived": true,
"created_at": "2023-11-07T05:31:56Z",
"external_id": "<string>",
"url": "<string>",
"failure_reason": "<string>",
"language": "<string>",
"digest": "<string>",
"reading_brief": "<string>",
"refresh_every": "daily",
"next_refresh_at": "2023-11-07T05:31:56Z",
"max_pages": 123,
"last_update_at": "2023-11-07T05:31:56Z",
"body": "<string>"
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "<string>",
"param": "<string>"
}
}Authorizations
Your secret key (pep_sk_…) from Settings → API. Keys are org-scoped; treat them like passwords.
Headers
Body
text, url, file, website Required for text; optional for url/website (defaults to the host, upgraded by the page title) and file (defaults to the filename).
Required for text. Max 500,000 characters.
Required for url (the page) and website (the site root). http(s) only.
website kind: page cap per refresh.
1 <= x <= 50file kind: the original filename (extension decides the extractor: txt, md, pdf, docx).
file kind: strict base64 of the file, max 10MB decoded.
Your sync key — unique per organization; makes POST an upsert.
255Two-letter hint; detection at refresh may override.
Up to 20 string values (≤500 chars each). Returned verbatim, never interpreted.
Show child attributes
Show child attributes
Optional reading guidance for the whole source: what the agent should specifically look for on every page. Steering only — facts still require a verbatim excerpt.
Scheduled-refresh cadence. url/website kinds only.
daily, weekly, monthly Agent slugs this source is active for — declarative: the activation set becomes exactly this list. Omit to leave activations untouched.
Response
Upserted an existing source (includes body for single-entry kinds).
"knowledge_source"text, url, file, website Aggregated from the source's entries: ready (everything ingested), updating (work in flight — poll), attention (usable with some failed entries), failed (nothing usable).
ready, updating, attention, failed Slugs of the agents this source is active for.
Show child attributes
Show child attributes
Entry counts by status (one entry per page for websites).
Show child attributes
Show child attributes
The page (url) or site root (website).
Single-entry kinds: why processing failed, human-readable. Websites report per-entry reasons under /entries.
What the agent understood from this source (generated after each refresh).
Reading guidance for the whole source: what the agent should specifically look for on every page. Steers extraction only — facts still require a verbatim excerpt from the page.
Scheduled-refresh cadence; null = manual only. url/website kinds only.
daily, weekly, monthly, null When the scheduler owes the next refresh (any refresh resets the clock). null when manual.
website kind only.
When the last refresh run landed — the freshness stamp.
Full text. Present on retrieve/create/update for text/url/file; websites read per-page content via /entries.

