Appearance
Documents
Documents are the knowledge base that powers the chat widget and semantic search. Every document is stored as markdown content with automatically generated vector embeddings for semantic retrieval.
Overview
The document system handles the full lifecycle: ingestion (from raw content or URLs), storage, embedding generation, semantic search indexing, and deletion. All operations are available via API with API key authentication.
API Access
All document endpoints support API key authentication:
GET /docs— List documents with paginationGET /docs/:id— Get a single documentPOST /docs/ingest— Ingest single or batch (raw content or URLs, auto-scrape, embeddings auto-generated)PUT /docs/:id— Update a documentDELETE /docs/:id— Delete a document and its embeddingsPOST /docs/batch-delete— Delete multiple documents at once
See the API Reference for full details.
Ingestion
Raw Content
Send markdown content directly. Embeddings are generated automatically on creation and update.
bash
curl -X POST https://api.canny.bot/api/docs/ingest \
-H "x-api-key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"title": "Product: Widget Pro", "content": "The Widget Pro is our flagship product..."}'
URL Auto-Scrape
Provide a URL without content and the system scrapes it using Firecrawl v2 with:
onlyMainContent— removes headers, navs, footersonlyCleanContent— LLM-based pass removing residual boilerplate (cookie banners, ads, social widgets)removeBase64Images— strips bloated base64 images- Image references (
) are stripped from the final markdown
bash
curl -X POST https://api.canny.bot/api/docs/ingest \
-H "x-api-key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/products/widget-pro"}'
Batch Ingestion
Send an array to ingest multiple documents in a single request. All items are processed in parallel.
bash
curl -X POST https://api.canny.bot/api/docs/ingest \
-H "x-api-key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '[
{"title": "Widget Pro", "content": "..."},
{"url": "https://example.com/products/widget-lite"},
{"title": "Gadget Max", "content": "...", "url": "https://...", "is_dynamic": true, "renew_interval_hours": 48}
]'
Dynamic Documents
Documents can be marked as dynamic to enable automatic content refresh from the source URL:
is_dynamic: true— enables auto-refreshrenew_interval_hours— hours between refreshes (default: 24, range: 1-720)
Dynamic documents are re-scraped and re-indexed at the configured interval. If a refresh fails, the last successful content is retained.
Embeddings
Embeddings are generated automatically using the semantic search plugin's indexer service:
- On create: embeddings are generated for the
contentfield, usingtitleas metadata - On update: embeddings are re-generated when content changes
- On delete: embeddings are removed before the document is deleted
Embedding generation is non-blocking — if it fails, the document is still created/updated and an error is logged.
Agentic Use Cases
Import a Product Catalog from an External API
- Fetch products from your product database API
- Map each product to
{ title, content, url }format - Send the array to
POST /docs/ingestin a single request - Verify with
GET /docsand test withGET /semantic-search/search
Sync Documents from a CMS
- List existing documents via
GET /docs - Compare with your CMS content
- Create new documents via
POST /docs/ingest - Update changed documents via
PUT /docs/:id - Delete removed documents via
POST /docs/batch-delete
Best Practices
- Use batch ingestion for bulk imports — it's faster than individual create calls
- Provide URLs when possible — the system handles scraping and markdown cleaning automatically
- Check account usage before large imports via
GET /account/status - Test search after ingestion via
GET /semantic-search/searchto verify embeddings work - Use batch delete for cleanup — it removes embeddings in parallel