Heppu APIv2.heppu.ai/api

Sources

Push one source, list them, delete them.

Upsert one

POST/api/v1/kb/sources
collectionIduuidrequired
externalIdstringrequired
Your id. Max 255. Upsert key inside the collection.
titlestringrequired
Max 500.
contentstringrequired
Markdown or plain text. Max 500k chars.
validFromRFC3339 | null
With timezone offset, e.g. 2026-09-01T00:00:00+03:00.
validUntilRFC3339 | null
Must be after validFrom.
contentRolecurrent | historical | null
metadataobject
Stored and returned. We add api_created_at / api_updated_at to it.
curl -X POST https://v2.heppu.ai/api/v1/kb/sources \
  -H "x-api-key: hep_..." -H "Content-Type: application/json" \
  -d '{
    "collectionId": "col_…",
    "externalId": "VIN-123",
    "title": "2021 Volvo XC60",
    "content": "# 2021 Volvo XC60\n\nPrice 34 900 €. 61 000 km. …",
    "validUntil": "2026-12-31T23:59:59+02:00"
  }'

201 new, 200 updated or unchanged:

{
  "data": {
    "documentId": "1f0a…",
    "externalId": "VIN-123",
    "status": "processing",
    "message": "Source queued for processing"
  },
  "meta": { "timestamp": "…" }
}

status is processing or unchanged. Note that on unchanged we still update the validity fields and contentRole, but not title or metadata. Change the content if you need those to move.

404 if the collection isn't yours. 400 with all validation issues joined.

List

GET/api/v1/kb/sources

Only sources created through the API. Uploads and crawls don't show here.

collectionIduuidrequired
Query param.
externalIdstring
Exact match.
statuspending | processing | completed | failed
limitint
Max 100.default 50
offsetint
default 0
{
  "data": {
    "sources": [
      {
        "id": "1f0a…",
        "externalId": "VIN-123",
        "title": "2021 Volvo XC60",
        "status": "completed",
        "chunkCount": 7,
        "fileSize": 4211,
        "error": null,
        "validFrom": null,
        "validUntil": "2026-12-31T21:59:59.000Z",
        "contentRole": "current",
        "metadata": { "api_created_at": "…" },
        "createdAt": "…",
        "updatedAt": "…"
      }
    ],
    "pagination": { "total": 128, "limit": 50, "offset": 0, "hasMore": true }
  },
  "meta": { "timestamp": "…" }
}

error is the processing error text when status is failed. Ordered by updatedAt desc.

Delete

DELETE/api/v1/kb/sources

Yes, a DELETE with a body.

{ "collectionId": "col_…", "externalIds": ["VIN-123", "VIN-124"] }

Max 100 ids. Removes them from this collection. If a source is also in another collection it survives there, otherwise the document, its chunks and its file go too.

{
  "data": {
    "deleted": 2,
    "documentsDeleted": 1,
    "deletedExternalIds": ["VIN-123", "VIN-124"],
    "notFound": ["VIN-999"],
    "message": "Removed 2 source(s) from collection col_…; 1 deleted entirely, 1 kept for other collections"
  },
  "meta": { "timestamp": "…" }
}

notFound is omitted when empty. Always 200, even if nothing matched.

On this page