import json
with open("/path/to/policy.pdf", "rb") as policy:
knowledge_result = client.context.ingest(
# Knowledge requests can include documents, app_knowledge, or both.
type="knowledge",
database="acme_corp",
collection="team_docs",
upsert=True,
# Use documents when HydraDB should parse PDFs, DOCX, CSV, Markdown, or text files.
documents=[("policy.pdf", policy, "application/pdf")],
document_metadata=json.dumps([
{
"id": "policy_main",
"metadata": {"department": "legal"},
"additional_metadata": {"source": "policy"},
}
]),
# Use app_knowledge when your app already extracted the source text/metadata.
app_knowledge=json.dumps([
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": {"text": "We agreed on three tiers..."},
"metadata": {"department": "product"},
"additional_metadata": {"channel": "pricing"},
}
]),
)
text_memory_result = client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
# Use text for raw notes or signals.
"text": "Prefers concise answers and dark mode.",
"infer": True,
"user_name": "Alex",
}
]),
)
conversation_memory_result = client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
# Use user_assistant_pairs for conversation history instead of text.
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{"user": "Can I get a refund?", "assistant": "Refunds are available within 30 days."},
],
"infer": False,
}
]),
)
const knowledgeResult = await client.context.ingest({
// Knowledge requests can include documents, app_knowledge, or both.
type: "knowledge",
database: "acme_corp",
collection: "team_docs",
upsert: true,
// Use documents when HydraDB should parse PDFs, DOCX, CSV, Markdown, or text files.
documents: [
{ path: "/path/to/policy.pdf", filename: "policy.pdf", contentType: "application/pdf" },
],
documentMetadata: JSON.stringify([
{
id: "policy_main",
metadata: { department: "legal" },
additional_metadata: { source: "policy" },
},
]),
// Use app_knowledge when your app already extracted the source text/metadata.
appKnowledge: JSON.stringify([
{
id: "slack_thread_001",
database: "acme_corp",
collection: "team_docs",
title: "Pricing discussion",
type: "slack",
content: { text: "We agreed on three tiers..." },
metadata: { department: "product" },
additional_metadata: { channel: "pricing" },
},
]),
});
const textMemoryResult = await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
// Use text for raw notes or signals.
text: "Prefers concise answers and dark mode.",
infer: true,
user_name: "Alex",
},
]),
});
const conversationMemoryResult = await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
// Use user_assistant_pairs for conversation history instead of text.
title: "Support conversation about refunds",
user_assistant_pairs: [
{ user: "Can I get a refund?", assistant: "Refunds are available within 30 days." },
],
infer: false,
},
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=knowledge" \
-F "database=acme_corp" \
-F "collection=team_docs" \
-F "upsert=true" \
-F "documents=@/path/to/policy.pdf" \
-F 'document_metadata=[
{
"id": "policy_main",
"metadata": { "department": "legal" },
"additional_metadata": { "source": "policy" }
}
]' \
-F 'app_knowledge=[
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": { "text": "We agreed on three tiers..." },
"metadata": { "department": "product" },
"additional_metadata": { "channel": "pricing" }
}
]'
# OR: memory from raw text.
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"text": "Prefers concise answers and dark mode.",
"infer": true,
"user_name": "Alex"
}
]'
# OR: memory from conversation pairs.
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{ "user": "Can I get a refund?", "assistant": "Refunds are available within 30 days." }
],
"infer": false
}
]'
{
"data": {
"failed_count": 0,
"message": "Success",
"results": [
{
"error": "",
"filename": "policy.pdf",
"id": "HydraDoc1234",
"relations_created": 5,
"status": "queued"
}
],
"success": true,
"success_count": 2
},
"error": {
"code": "DATABASE_NOT_FOUND",
"message": "Database not found"
},
"meta": {
"collection": "team_docs",
"database": "acme_corp",
"latency_ms": 12.3,
"request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
"source_type": "file",
"sub_tenant_id": "sub_tenant_4567",
"tenant_id": "tenant_1234"
},
"success": true
}{
"detail": {
"deprecated": true,
"deprecated_field": "tenant_id",
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"preferred_field": "database",
"success": true
}
}{
"detail": {
"deprecated": true,
"deprecated_field": "tenant_id",
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"preferred_field": "database",
"success": true
}
}{
"detail": {
"deprecated": true,
"deprecated_field": "tenant_id",
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"preferred_field": "database",
"success": true
}
}Ingest Context
Ingestion endpoint for knowledge (documents, app sources) and user memories.
import json
with open("/path/to/policy.pdf", "rb") as policy:
knowledge_result = client.context.ingest(
# Knowledge requests can include documents, app_knowledge, or both.
type="knowledge",
database="acme_corp",
collection="team_docs",
upsert=True,
# Use documents when HydraDB should parse PDFs, DOCX, CSV, Markdown, or text files.
documents=[("policy.pdf", policy, "application/pdf")],
document_metadata=json.dumps([
{
"id": "policy_main",
"metadata": {"department": "legal"},
"additional_metadata": {"source": "policy"},
}
]),
# Use app_knowledge when your app already extracted the source text/metadata.
app_knowledge=json.dumps([
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": {"text": "We agreed on three tiers..."},
"metadata": {"department": "product"},
"additional_metadata": {"channel": "pricing"},
}
]),
)
text_memory_result = client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
# Use text for raw notes or signals.
"text": "Prefers concise answers and dark mode.",
"infer": True,
"user_name": "Alex",
}
]),
)
conversation_memory_result = client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
# Use user_assistant_pairs for conversation history instead of text.
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{"user": "Can I get a refund?", "assistant": "Refunds are available within 30 days."},
],
"infer": False,
}
]),
)
const knowledgeResult = await client.context.ingest({
// Knowledge requests can include documents, app_knowledge, or both.
type: "knowledge",
database: "acme_corp",
collection: "team_docs",
upsert: true,
// Use documents when HydraDB should parse PDFs, DOCX, CSV, Markdown, or text files.
documents: [
{ path: "/path/to/policy.pdf", filename: "policy.pdf", contentType: "application/pdf" },
],
documentMetadata: JSON.stringify([
{
id: "policy_main",
metadata: { department: "legal" },
additional_metadata: { source: "policy" },
},
]),
// Use app_knowledge when your app already extracted the source text/metadata.
appKnowledge: JSON.stringify([
{
id: "slack_thread_001",
database: "acme_corp",
collection: "team_docs",
title: "Pricing discussion",
type: "slack",
content: { text: "We agreed on three tiers..." },
metadata: { department: "product" },
additional_metadata: { channel: "pricing" },
},
]),
});
const textMemoryResult = await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
// Use text for raw notes or signals.
text: "Prefers concise answers and dark mode.",
infer: true,
user_name: "Alex",
},
]),
});
const conversationMemoryResult = await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
// Use user_assistant_pairs for conversation history instead of text.
title: "Support conversation about refunds",
user_assistant_pairs: [
{ user: "Can I get a refund?", assistant: "Refunds are available within 30 days." },
],
infer: false,
},
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=knowledge" \
-F "database=acme_corp" \
-F "collection=team_docs" \
-F "upsert=true" \
-F "documents=@/path/to/policy.pdf" \
-F 'document_metadata=[
{
"id": "policy_main",
"metadata": { "department": "legal" },
"additional_metadata": { "source": "policy" }
}
]' \
-F 'app_knowledge=[
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": { "text": "We agreed on three tiers..." },
"metadata": { "department": "product" },
"additional_metadata": { "channel": "pricing" }
}
]'
# OR: memory from raw text.
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"text": "Prefers concise answers and dark mode.",
"infer": true,
"user_name": "Alex"
}
]'
# OR: memory from conversation pairs.
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{ "user": "Can I get a refund?", "assistant": "Refunds are available within 30 days." }
],
"infer": false
}
]'
{
"data": {
"failed_count": 0,
"message": "Success",
"results": [
{
"error": "",
"filename": "policy.pdf",
"id": "HydraDoc1234",
"relations_created": 5,
"status": "queued"
}
],
"success": true,
"success_count": 2
},
"error": {
"code": "DATABASE_NOT_FOUND",
"message": "Database not found"
},
"meta": {
"collection": "team_docs",
"database": "acme_corp",
"latency_ms": 12.3,
"request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
"source_type": "file",
"sub_tenant_id": "sub_tenant_4567",
"tenant_id": "tenant_1234"
},
"success": true
}{
"detail": {
"deprecated": true,
"deprecated_field": "tenant_id",
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"preferred_field": "database",
"success": true
}
}{
"detail": {
"deprecated": true,
"deprecated_field": "tenant_id",
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"preferred_field": "database",
"success": true
}
}{
"detail": {
"deprecated": true,
"deprecated_field": "tenant_id",
"error_code": "VALIDATION_ERROR",
"message": "Request validation failed",
"preferred_field": "database",
"success": true
}
}type=knowledge:
- Documents - Use the
documentsfield for binary uploads (PDF, DOCX, CSV, MD, TXT) that HydraDB should parse. - App Sources - Use
app_knowledgefor pre-extracted JSON content (Slack threads, Notion pages, emails, tickets). Read more about ingesting knowledge from your apps.
type=memory
Use memories for per-user content, scoped with collection. Set infer: true to let HydraDB extract preferences from raw signals, or infer: false to store the text verbatim. Read more about ingesting memories.
database and collection are the current field names (formerly tenant_id and sub_tenant_id). The old names remain accepted as deprecated aliases for full backward compatibility.import json
with open("/path/to/policy.pdf", "rb") as policy:
knowledge_result = client.context.ingest(
# Knowledge requests can include documents, app_knowledge, or both.
type="knowledge",
database="acme_corp",
collection="team_docs",
upsert=True,
# Use documents when HydraDB should parse PDFs, DOCX, CSV, Markdown, or text files.
documents=[("policy.pdf", policy, "application/pdf")],
document_metadata=json.dumps([
{
"id": "policy_main",
"metadata": {"department": "legal"},
"additional_metadata": {"source": "policy"},
}
]),
# Use app_knowledge when your app already extracted the source text/metadata.
app_knowledge=json.dumps([
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": {"text": "We agreed on three tiers..."},
"metadata": {"department": "product"},
"additional_metadata": {"channel": "pricing"},
}
]),
)
text_memory_result = client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
# Use text for raw notes or signals.
"text": "Prefers concise answers and dark mode.",
"infer": True,
"user_name": "Alex",
}
]),
)
conversation_memory_result = client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
# Use user_assistant_pairs for conversation history instead of text.
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{"user": "Can I get a refund?", "assistant": "Refunds are available within 30 days."},
],
"infer": False,
}
]),
)
const knowledgeResult = await client.context.ingest({
// Knowledge requests can include documents, app_knowledge, or both.
type: "knowledge",
database: "acme_corp",
collection: "team_docs",
upsert: true,
// Use documents when HydraDB should parse PDFs, DOCX, CSV, Markdown, or text files.
documents: [
{ path: "/path/to/policy.pdf", filename: "policy.pdf", contentType: "application/pdf" },
],
documentMetadata: JSON.stringify([
{
id: "policy_main",
metadata: { department: "legal" },
additional_metadata: { source: "policy" },
},
]),
// Use app_knowledge when your app already extracted the source text/metadata.
appKnowledge: JSON.stringify([
{
id: "slack_thread_001",
database: "acme_corp",
collection: "team_docs",
title: "Pricing discussion",
type: "slack",
content: { text: "We agreed on three tiers..." },
metadata: { department: "product" },
additional_metadata: { channel: "pricing" },
},
]),
});
const textMemoryResult = await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
// Use text for raw notes or signals.
text: "Prefers concise answers and dark mode.",
infer: true,
user_name: "Alex",
},
]),
});
const conversationMemoryResult = await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
// Use user_assistant_pairs for conversation history instead of text.
title: "Support conversation about refunds",
user_assistant_pairs: [
{ user: "Can I get a refund?", assistant: "Refunds are available within 30 days." },
],
infer: false,
},
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=knowledge" \
-F "database=acme_corp" \
-F "collection=team_docs" \
-F "upsert=true" \
-F "documents=@/path/to/policy.pdf" \
-F 'document_metadata=[
{
"id": "policy_main",
"metadata": { "department": "legal" },
"additional_metadata": { "source": "policy" }
}
]' \
-F 'app_knowledge=[
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": { "text": "We agreed on three tiers..." },
"metadata": { "department": "product" },
"additional_metadata": { "channel": "pricing" }
}
]'
# OR: memory from raw text.
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"text": "Prefers concise answers and dark mode.",
"infer": true,
"user_name": "Alex"
}
]'
# OR: memory from conversation pairs.
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{ "user": "Can I get a refund?", "assistant": "Refunds are available within 30 days." }
],
"infer": false
}
]'
Upload in-memory text as a .txt file
If you already have text in memory, create a file-like object and upload it through documents as a text/plain .txt file.
import io
import json
text = """Q4 planning notes
- Launch checklist is owned by Priya.
- Legal review is due by Friday.
"""
# Create a file-like object in memory. No local .txt file is required.
txt_file = io.BytesIO(text.encode("utf-8"))
response = client.context.ingest(
type="knowledge",
database="acme_corp",
collection="team_docs",
documents=[("meeting-notes.txt", txt_file, "text/plain")],
document_metadata=json.dumps([
{"id": "meeting_notes_q4", "metadata": {"department": "product"}}
]),
)
const text = `Q4 planning notes
- Launch checklist is owned by Priya.
- Legal review is due by Friday.
`;
const response = await client.context.ingest({
type: "knowledge",
database: "acme_corp",
collection: "team_docs",
documents: [
{
filename: "meeting-notes.txt",
contentType: "text/plain",
data: Buffer.from(text, "utf-8"),
},
],
documentMetadata: JSON.stringify([
{ id: "meeting_notes_q4", metadata: { department: "product" } },
]),
});
import io
import json
import requests
text = """Q4 planning notes
- Launch checklist is owned by Priya.
- Legal review is due by Friday.
"""
# Create a file-like object in memory. No local .txt file is required.
txt_file = io.BytesIO(text.encode("utf-8"))
response = requests.post(
"https://api.hydradb.com/context/ingest",
headers={
"Authorization": "Bearer <your_api_key>",
"API-Version": "2",
},
data={
"type": "knowledge",
"database": "acme_corp",
"collection": "team_docs",
"document_metadata": json.dumps([
{"id": "meeting_notes_q4", "metadata": {"department": "product"}}
]),
},
files={
"documents": ("meeting-notes.txt", txt_file, "text/plain"),
},
)
response.raise_for_status()
Important form fields
| Name | Description |
|---|---|
Use singular "memory" when writing memories. (default="knowledge") | |
Target database. Formerly tenant_id; the tenant_id alias is still accepted (deprecated). | |
Logical partition inside the database. Formerly sub_tenant_id; the sub_tenant_id alias is still accepted (deprecated). (default="" - default collection) | |
Replace existing sources with the same ID. Set to false to error on conflict. (default=true) | |
Binary uploads, knowledge only. Required when type=knowledge and you want HydraDB to parse documents. Omit when ingesting memories. (default=[]) | |
One entry per file in documents, in the same order. If omitted, documents index with inferred defaults such as filename/title. See the item shape below. | |
Pre-extracted source objects (Slack, Notion, web pages, etc.), knowledge only. See the app_knowledge item shape below. | |
Map of source id → your own entities + relations - replaces LLM graph extraction for each keyed source. Works for type=knowledge (key = a document_metadata id or app_knowledge item id) and type=memory (key = a memory id). See Bring Your Own Graph and the shape below. | |
Memory items, memory only. Required and non-empty when type=memory. Use plural memories for the form field, even though type is singular memory. See the memories item shape below. |
-
idmust not contain a comma (,). The comma is reserved as the id separator on Ingestion Status (GET /context/status?ids=a,b), so anidcontaining a comma cannot be looked up unambiguously. This applies to everyidyou supply —document_metadata,app_knowledge, andmemoriesitems. Ingesting an item whoseidcontains a comma is rejected with a400. -
202 Acceptedmeans queued, not indexed. Ingestion is asynchronous. A successful response only confirms your sources were accepted, not that they are ready to query. Before querying, pollGET /context/statuswith the returned IDs until each source reachescompletedorerrored. Alternatively, register a webhook forindexing.status_changedevents (see Webhooks).
Common use-cases and their configurations
Document metadata
Per-document metadata (id, metadata, additional_metadata, title, etc.) can be passed alongside each uploaded document to control indexing, filtering, and display. See the field reference below.
Knowledge documents - upload PDFs, DOCX, CSV, markdown, or text
Knowledge documents - upload PDFs, DOCX, CSV, markdown, or text
import json
with open("/path/to/policy.pdf", "rb") as f1, open("/path/to/runbook.pdf", "rb") as f2:
result = client.context.ingest(
type="knowledge",
database="acme_corp",
documents=[
("policy.pdf", f1, "application/pdf"),
("runbook.pdf", f2, "application/pdf"),
],
document_metadata=json.dumps([
{"id": "policy_main", "metadata": {"department": "legal"}},
{"id": "runbook_deploy", "metadata": {"department": "ops"}},
]),
)
const result = await client.context.ingest({
type: "knowledge",
database: "acme_corp",
documents: [
{ path: "/path/to/policy.pdf", filename: "policy.pdf", contentType: "application/pdf" },
{ path: "/path/to/runbook.pdf", filename: "runbook.pdf", contentType: "application/pdf" },
],
documentMetadata: JSON.stringify([
{ id: "policy_main", metadata: { department: "legal" } },
{ id: "runbook_deploy", metadata: { department: "ops" } },
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=knowledge" \
-F "database=acme_corp" \
-F "documents=@/path/to/policy.pdf" \
-F "documents=@/path/to/runbook.pdf" \
-F 'document_metadata=[
{ "id": "policy_main", "metadata": { "department": "legal" } },
{ "id": "runbook_deploy", "metadata": { "department": "ops" } }
]'
| Field | Description |
|---|---|
Optional context ID. If set, becomes the id for this document (use your app’s document ID for parity). Must not contain a comma (,) - it is reserved as the id separator on /context/status?ids=. | |
Database-schema fields for filtering and search. Keys must be declared in database_metadata_schema. (default={}) | |
Free-form per-document fields for display or bookkeeping. To filter on these at search time, nest under metadata_filters.additional_metadata. (default={}) | |
| Override the source title shown in search results. (default=filename) | |
| Override the source type shown in search results. (default=inferred) | |
| Override the canonical URL. | |
| ISO-8601 timestamp override. (default=upload time) | |
Declare forceful relations to other sources. Shape: { "ids": ["...", "..."] }. Surfaced via additional_context in mode: "thinking" search. |
App sources - index text from your workspace or personal apps
App sources - index text from your workspace or personal apps
import json
client.context.ingest(
type="knowledge",
database="acme_corp",
collection="team_docs",
app_knowledge=json.dumps([
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": {"text": "We agreed on three tiers..."},
"metadata": {"channel": "product"},
}
]),
)
await client.context.ingest({
type: "knowledge",
database: "acme_corp",
collection: "team_docs",
appKnowledge: JSON.stringify([
{
id: "slack_thread_001",
database: "acme_corp",
collection: "team_docs",
title: "Pricing discussion",
type: "slack",
content: { text: "We agreed on three tiers..." },
metadata: { channel: "product" },
},
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=knowledge" \
-F "database=acme_corp" \
-F "collection=team_docs" \
-F 'app_knowledge=[
{
"id": "slack_thread_001",
"database": "acme_corp",
"collection": "team_docs",
"title": "Pricing discussion",
"type": "slack",
"content": { "text": "We agreed on three tiers..." },
"metadata": { "channel": "product" }
}
]'
| Field | Description |
|---|---|
Context ID. Treated as the upsert key. Send an empty string to have one generated upstream. Must not contain a comma (,) - it is reserved as the id separator on /context/status?ids=. | |
Target database. Must match the form-level database. Formerly tenant_id; the tenant_id alias is still accepted (deprecated). | |
Logical partition inside the database. Must match the form-level collection. Formerly sub_tenant_id; the sub_tenant_id alias is still accepted (deprecated). | |
| Short title or subject shown in search results. | |
Source category (slack, notion, gmail, webpage, etc.). Used for filtering and display. | |
| Optional long-form description. | |
| Canonical URL or reference link. | |
| ISO-8601 timestamp (creation or last-updated). | |
Content payload. Use { "text": "..." } for plain text. Required for app sources. | |
Database-schema fields. (default={}) | |
Free-form per-document fields. (default={}) | |
Optional related attachments. (default=[]) | |
Forceful relations, same shape as on metadata. |
3. User memories - store notes or infer user preferences
3. User memories - store notes or infer user preferences
import json
client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
"text": "Prefers dark mode and short answers.",
"infer": True,
"user_name": "Alex",
}
]),
)
await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
text: "Prefers dark mode and short answers.",
infer: true,
user_name: "Alex",
},
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"text": "Prefers dark mode and short answers.",
"infer": true,
"user_name": "Alex"
}
]'
| Field | Description |
|---|---|
Optional unique ID. Acts as the upsert key. Must not contain a comma (,) - it is reserved as the id separator on /context/status?ids=. (default=auto-generated) | |
Short label for display in /context/list and search hits as source.title. (default=truncated text) | |
Raw text or markdown content. Required unless user_assistant_pairs is provided. | |
Conversation pairs { user, assistant }. Required unless text is provided. | |
Treat text as markdown for chunking. (default=false) | |
When true, HydraDB extracts the underlying preference from raw signal. (default=false) | |
Guides extraction when infer: true. Ignored when infer: false. | |
The user’s name. Feeds inference. (default="User") | |
| TTL in seconds. Memory stops surfacing after expiry. | |
Database-schema fields as a JSON-stringified object (e.g. "{\"department\":\"legal\"}"). Unlike metadata and app_knowledge, memory items take this as a string, not an object. (default="") | |
Free-form per-document fields as a JSON-stringified object. Same string-vs-object difference as metadata above. (default="") | |
Forceful relations within the Memories store. Shape: { "ids": ["...", "..."] }. |
4. Chat/LLM conversation pairs - store chat history or support context
4. Chat/LLM conversation pairs - store chat history or support context
import json
client.context.ingest(
type="memory",
database="acme_corp",
collection="user_alex",
memories=json.dumps([
{
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{"user": "Can I get a refund?", "assistant": "Refunds are available within 30 days."},
],
"infer": False,
}
]),
)
await client.context.ingest({
type: "memory",
database: "acme_corp",
collection: "user_alex",
memories: JSON.stringify([
{
title: "Support conversation about refunds",
user_assistant_pairs: [
{ user: "Can I get a refund?", assistant: "Refunds are available within 30 days." },
],
infer: false,
},
]),
});
curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=memory" \
-F "database=acme_corp" \
-F "collection=user_alex" \
-F 'memories=[
{
"title": "Support conversation about refunds",
"user_assistant_pairs": [
{ "user": "Can I get a refund?", "assistant": "Refunds are available within 30 days." }
],
"infer": false
}
]'
Bring your own graph - supply entities and relations
Bring your own graph - supply entities and relations
graph_payload is a map of source id → graph that replaces LLM graph extraction for each keyed source. For type=knowledge, the key is a document_metadata id or an app_knowledge item id; for type=memory, the key is a memory id. Keyed sources are still chunked and embedded, so they stay searchable. See Bring Your Own Graph for the full guide.curl -X POST 'https://api.hydradb.com/context/ingest' \
-H "Authorization: Bearer <your_api_key>" \
-H "API-Version: 2" \
-F "type=knowledge" \
-F "database=acme_corp" \
-F "documents=@/path/to/policy.pdf" \
-F 'document_metadata=[{ "id": "billing-policy-doc" }]' \
-F 'graph_payload={
"billing-policy-doc": {
"entities": {
"alice": { "name": "Alice Carter", "type": "PERSON", "namespace": "employees" },
"billing": { "name": "Billing Policy", "type": "POLICY", "namespace": "policies" }
},
"relations": [
{ "source": "alice", "target": "billing", "predicate": "OWNS",
"context": "Alice Carter owns the billing policy." }
]
}
}'
import json
with open("/path/to/policy.pdf", "rb") as f:
client.context.ingest(
type="knowledge",
database="acme_corp",
documents=[("policy.pdf", f, "application/pdf")],
document_metadata=json.dumps([{"id": "billing-policy-doc"}]),
graph_payload=json.dumps({
"billing-policy-doc": {
"entities": {
"alice": {"name": "Alice Carter", "type": "PERSON", "namespace": "employees"},
"billing": {"name": "Billing Policy", "type": "POLICY", "namespace": "policies"},
},
"relations": [
{"source": "alice", "target": "billing", "predicate": "OWNS",
"context": "Alice Carter owns the billing policy."},
],
}
}),
)
await client.context.ingest({
type: "knowledge",
database: "acme_corp",
documents: [{ path: "/path/to/policy.pdf", filename: "policy.pdf", contentType: "application/pdf" }],
documentMetadata: JSON.stringify([{ id: "billing-policy-doc" }]),
graphPayload: JSON.stringify({
"billing-policy-doc": {
entities: {
alice: { name: "Alice Carter", type: "PERSON", namespace: "employees" },
billing: { name: "Billing Policy", type: "POLICY", namespace: "policies" },
},
relations: [
{ source: "alice", target: "billing", predicate: "OWNS",
context: "Alice Carter owns the billing policy." },
],
},
}),
});
| Field | Description |
|---|---|
Top-level key: a document_metadata id or app_knowledge item id for type=knowledge, or a memory id for type=memory. Value is that source’s graph. A key matching no source returns 400. | |
Map keyed by a caller-local id; each value is an entity. The key is only a handle for relations to reference - it is not stored. | |
| Entity name. Normalized (lowercased) server-side so it matches at query time. ≤ 256 chars. | |
Entity type (e.g. PERSON, POLICY). Stored as supplied. | |
| Logical grouping for the entity. Stored as supplied. | |
| Optional external id (email, URL, etc.) - display only. | |
| Edges referencing entity-map keys. | |
| Entity-map key of the source entity. | |
| Entity-map key of the target entity. | |
| Relationship label, any plain string. ≤ 256 chars. | |
| Optional sentence supporting the edge. ≤ 2,000 chars. | |
| Optional timing info (e.g. “since 2021”, “in Q3”). |
document_metadata id or app_knowledge item id for type=knowledge, or a memory id for type=memory, in the same request; attach graphs to multiple sources at once. Extraction is skipped for keyed sources. Caps per graph: ≤ 5,000 entities, ≤ 10,000 relations, ≤ 500 relations per entity; over-cap returns 400. Graphs survive re-ingest (re-upload or connector re-sync re-applies the stored graph).Some important notes
- Async indexing.
202 Acceptedmeans HydraDB queued the work, not that content is searchable. Poll Ingestion Status untilindexing_statusreachesgraph_creation(searchable) orcompleted(graph-ready). - Multipart, not JSON. This endpoint uses
multipart/form-data. Stringify all JSON arrays (metadata,app_knowledge,memories) before placing them in the form field. - Declare hot schema fields upfront. Put frequently filtered fields in
metadata, define them indatabase_metadata_schemawithenable_match: true, and useadditional_metadatafor free-form display/bookkeeping fields. Define filterable fields when creating the database via Create Database. Additive schema updates exist, but newly added dense/sparse metadata lanes are not backfilled into existing Milvus collections. - Memory vs knowledge. Use
type: "memory"for memory ingestion, listing, and deletion. Usetype: "all"onPOST /querywhen results should combine both. The multipart field name for memories is alwaysmemories. - Collection defaulting. Omitting
collectionwrites to the default collection. List available collections with List Collections.
- Always check ingestion status to ensure context is ready to be retrieved
- Query once context is ready
- Inspect: List Documents helps you fetch titles and descriptions of ingested context
- Inspect: Fetch Content helps you fetch full context of a document, memory, knowledge item
- Cleanup: Delete Context
Authorizations
API key sent as a Bearer token: "Bearer prefix.secret"
Body
Content type: 'knowledge' or 'memory' | Database (canonical name for the tenant scope) | Collection (canonical name for the sub-tenant scope) | Deprecated alias for database | Deprecated alias for collection | Upsert existing content (true/false/1/0) | Knowledge files to ingest (repeatable; type=knowledge) | Per-document metadata as a JSON array (type=knowledge) | App-knowledge items as a JSON array (type=knowledge) | Memory items as a JSON array (type=memory) | Optional bring-your-own-graph payload as JSON
Response
Accepted
Show child attributes
Show child attributes
{
"failed_count": 0,
"message": "Success",
"results": [
{
"error": "",
"filename": "policy.pdf",
"id": "HydraDoc1234",
"relations_created": 5,
"status": "queued"
}
],
"success": true,
"success_count": 2
}
Error message, empty string on success.
Show child attributes
Show child attributes
{
"code": "DATABASE_NOT_FOUND",
"message": "Database not found"
}
Show child attributes
Show child attributes
{
"collection": "team_docs",
"database": "acme_corp",
"latency_ms": 12.3,
"request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
"source_type": "file",
"sub_tenant_id": "sub_tenant_4567",
"tenant_id": "tenant_1234"
}
Whether the request succeeded.
true
Was this page helpful?