Knowledge base — sources and indexed text
The agent's hand-authored sources — a problem, its root cause and the solution steps, written by hand instead of uploaded — and a library file's indexed text: literally what the agent searches.
Download the full API pública projection: openapi.json.
Give the agent something to quote explains this resource in prose, with runnable examples.
| Method | Path | What it does |
|---|---|---|
GET | /kb-files/{id}/text | Full extracted (indexed) text of a knowledge file |
POST | /kb/rollup/refresh | Refresh KB chunk hits rollup |
GET | /kb/sources | List KB sources |
POST | /kb/sources | Create a KB source |
DELETE | /kb/sources/{id} | Delete a KB source |
GET | /kb/sources/{id} | Get KB source |
PUT | /kb/sources/{id} | Update a KB source |
POST | /kb/sources/{id}/embed | Embed manual KB entry into documentation_chunks |
POST | /kb/sources/{id}/reingest | Re-ingest KB source |
POST | /kb/sources/{id}/revoke | Revoke KB source |
GET /kb-files/{id}/text
Full extracted (indexed) text of a knowledge file
Every ingested chunk in document order — literally what search_knowledge_base searches. text is null when nothing is indexed yet.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes |
curl https://api.vitrinadev.com/api/v1/kb-files/<id>/text \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"text": "Todos los vehículos nuevos incluyen 3 años o 100.000 km de garantía de fábrica…"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /kb/rollup/refresh
Refresh KB chunk hits rollup
Refreshes the kb_chunk_hits materialised view — how often each chunk was actually retrieved and cited, behind the "most-used knowledge" reporting. Synchronous; safe to call repeatedly.
curl -X POST https://api.vitrinadev.com/api/v1/kb/rollup/refresh \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"refreshed": true
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /kb/sources
List KB sources
Every manual KB source in the workspace, newest first. status filters to active (approved + pending — everything not revoked), revoked, or all; omit it for active. tag filters to sources carrying that exact tag. Paginated with limit/offset (default 50, max 200).
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
tenant_id | query | uuid | no | |
status | query | active \ | revoked \ | all |
tag | query | string | no | mín. 1 |
limit | query | integer | no | ≥ 1, ≤ 200, por defecto 50 |
offset | query | integer | null | no | ≥ 0, por defecto 0 |
curl https://api.vitrinadev.com/api/v1/kb/sources \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"id": "a5a5a5a5-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"status": "approved",
"tags": [
"horarios",
"atencion"
],
"summary": {
"title": "Horario de atención",
"problem": "El cliente pregunta el horario de atención",
"root_cause": null,
"solution_steps": [
"Confirmar el horario: lunes a viernes de 9:00 a 19:00",
"Ofrecer agendar una cita si corresponde"
],
"product": null,
"language": "es",
"notes": null
},
"chunk_ids": [
3801
],
"verified_until": null,
"error": null,
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"ticket_id": null,
"help_center_article_id": null,
"help_center_locale": null,
"help_center_url": null,
"created_at": "2026-09-10T12:00:00.000Z",
"updated_at": "2026-09-10T12:05:00.000Z"
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50
},
"offset": 0
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /kb/sources
Create a KB source
Hand-author a KB entry: summary is the structured shape the agent quotes from (title, problem, optional root_cause, solution_steps — 1 to 50 steps), tags is 1 to 20 free-form labels, and verified_until optionally marks when the answer should be reviewed again.
The row is born status: "pending" and with NO chunks — creating it does not make it retrievable. Nothing is searchable until POST /kb/sources/\{id\}/embed runs (typically after review sets status: "approved" via PUT). Answers 201. Fires kb.source.create.
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
summary | object | yes | |
tags | string[] | yes | |
verified_until | string | null | — | date-time |
curl -X POST https://api.vitrinadev.com/api/v1/kb/sources \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"summary": {
"title": "Horario de atención",
"problem": "El cliente pregunta el horario de atención",
"solution_steps": [
"Confirmar el horario: lunes a viernes de 9:00 a 19:00",
"Ofrecer agendar una cita si corresponde"
]
},
"tags": [
"horarios",
"atencion"
]
}'Example response (201)
{
"data": {
"id": "a5a5a5a5-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"status": "pending",
"tags": [
"horarios",
"atencion"
],
"summary": {
"title": "Horario de atención",
"problem": "El cliente pregunta el horario de atención",
"root_cause": null,
"solution_steps": [
"Confirmar el horario: lunes a viernes de 9:00 a 19:00",
"Ofrecer agendar una cita si corresponde"
],
"product": null,
"language": "es",
"notes": null
},
"chunk_ids": [],
"verified_until": null,
"error": null,
"conversation_id": null,
"ticket_id": null,
"help_center_article_id": null,
"help_center_locale": null,
"help_center_url": null,
"created_at": "2026-09-10T12:00:00.000Z",
"updated_at": "2026-09-10T12:05:00.000Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /kb/sources/{id}
Delete a KB source
A HARD delete — unlike DELETE /kb-files/\{id\} (soft), the row and its embedded chunks are gone; retrieval can no longer return it and there is no un-delete. To stop the source being retrieved WITHOUT losing it, prefer POST /kb/sources/\{id\}/revoke (status: "revoked", row kept). Fires kb.source.delete. 204.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes | mín. 1 |
curl -X DELETE https://api.vitrinadev.com/api/v1/kb/sources/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /kb/sources/{id}
Get KB source
The full row, including its summary and chunk_ids.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes | mín. 1 |
curl https://api.vitrinadev.com/api/v1/kb/sources/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"id": "a5a5a5a5-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"status": "approved",
"tags": [
"horarios",
"atencion"
],
"summary": {
"title": "Horario de atención",
"problem": "El cliente pregunta el horario de atención",
"root_cause": null,
"solution_steps": [
"Confirmar el horario: lunes a viernes de 9:00 a 19:00",
"Ofrecer agendar una cita si corresponde"
],
"product": null,
"language": "es",
"notes": null
},
"chunk_ids": [
3801
],
"verified_until": null,
"error": null,
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"ticket_id": null,
"help_center_article_id": null,
"help_center_locale": null,
"help_center_url": null,
"created_at": "2026-09-10T12:00:00.000Z",
"updated_at": "2026-09-10T12:05:00.000Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /kb/sources/{id}
Update a KB source
Every field optional; at least one is required (an empty body is a 400). This is the review step: setting status: "approved" is what the manual-authoring flow uses to mark a draft entry ready — it does NOT re-embed by itself, so a status change alone does not update what the agent retrieves. Call POST /kb/sources/\{id\}/embed after, whether or not summary changed, to push the update into documentation_chunks. Fires kb.source.update.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes | mín. 1 |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
summary | object | — | |
tags | string[] | — | |
status | pending \ | approved \ | revoked \ |
verified_until | string | null | — | date-time |
curl -X PUT https://api.vitrinadev.com/api/v1/kb/sources/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "approved"
}'Example response (200)
{
"data": {
"id": "a5a5a5a5-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"status": "approved",
"tags": [
"horarios",
"atencion"
],
"summary": {
"title": "Horario de atención",
"problem": "El cliente pregunta el horario de atención",
"root_cause": null,
"solution_steps": [
"Confirmar el horario: lunes a viernes de 9:00 a 19:00",
"Ofrecer agendar una cita si corresponde"
],
"product": null,
"language": "es",
"notes": null
},
"chunk_ids": [
3801
],
"verified_until": null,
"error": null,
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"ticket_id": null,
"help_center_article_id": null,
"help_center_locale": null,
"help_center_url": null,
"created_at": "2026-09-10T12:00:00.000Z",
"updated_at": "2026-09-10T12:05:00.000Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /kb/sources/{id}/embed
Embed manual KB entry into documentation_chunks
Renders the source’s summary to markdown and (re-)embeds it, synchronously. Deletes any chunks this source previously produced before inserting the new ones, so it is safe to call repeatedly — a source never doubles up in retrieval. This is the ONLY thing that makes a manual entry (or an edit to one) actually retrievable; a source with no summary is a 400. Fires kb.source.embed.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes | mín. 1 |
curl -X POST https://api.vitrinadev.com/api/v1/kb/sources/<id>/embed \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"kb_source_id": "a5a5a5a5-0000-4000-8000-000000000001",
"chunks": 2,
"chunk_ids": [
3801,
3802
]
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /kb/sources/{id}/reingest
Re-ingest KB source
Re-queues the source’s LINKED CONVERSATION through the automatic kb-ingestion worker (the same path a resolved ticket triggers) — for a source with no conversation_id (a purely manual entry) this is a 400; use POST /kb/sources/\{id\}/embed instead, which re-embeds the stored summary directly. Answers 202 — the work happens on the worker, not synchronously.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes | mín. 1 |
curl -X POST https://api.vitrinadev.com/api/v1/kb/sources/<id>/reingest \
-H "Authorization: Bearer $VITRINA_KEY"Example response (202)
{
"data": {
"enqueued": true,
"kb_source_id": "a5a5a5a5-0000-4000-8000-000000000001"
}
}Answers: 202 · 400 · 401 · 403 · 404 · 409 · 429
POST /kb/sources/{id}/revoke
Revoke KB source
The reversible alternative to delete: sets status: "revoked". The row and its chunks survive, but a revoked source is excluded from the default GET /kb/sources list (pass status=all to see it) — this endpoint does not itself purge documentation_chunks, so re-approve and re-embed to bring it back rather than re-creating it. 204.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | string | yes | mín. 1 |
curl -X POST https://api.vitrinadev.com/api/v1/kb/sources/<id>/revoke \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
Integrations · Meta Ads
The Meta Ads account connection: start it, resolve the account selection when there is more than one, disconnect it, and read the workspace's click-to-WhatsApp ads.
Knowledge base — files
The workspace's uploaded document library: one is uploaded or authored from a URL, then attached to one or more agents.