Skip to main content
This guide walks through installing the SDK, authenticating, uploading documents, and running a search — in a few minutes.
Charcoal is currently invite-only. Contact us for access.

Install

npm install @charcoalhq/sdk

Authenticate

All API requests require an API key passed as a Bearer token in the Authorization header. Set it as an environment variable:
export CHARCOAL_API_KEY="your_api_key_here"
Or pass it directly when creating the client:
import Charcoal from "@charcoalhq/sdk";

const client = new Charcoal({ apiKey: process.env.CHARCOAL_API_KEY });
Keep your API keys secret. Do not expose them in client-side code or commit them to version control.

Managing API keys

List, create, and delete keys via the /v1/api_keys endpoints:
# List
curl https://api.withcharcoal.com/v1/api_keys \
  -H "Authorization: Bearer $CHARCOAL_API_KEY"

# Create
curl -X POST https://api.withcharcoal.com/v1/api_keys \
  -H "Authorization: Bearer $CHARCOAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production"}'

# Delete
curl -X DELETE https://api.withcharcoal.com/v1/api_keys/1 \
  -H "Authorization: Bearer $CHARCOAL_API_KEY"
The create response includes the full key in raw_key. This is the only time the full key is returned, so store it securely.

Upload documents

Create a namespace and upload documents in a single request. Each document needs a unique id. The namespace is created automatically if it doesn’t exist.
curl -X POST https://api.withcharcoal.com/v1/namespaces/my-docs/documents \
  -H "Authorization: Bearer $CHARCOAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "documents": [
      {
        "id": "doc-1",
        "title": "Getting Started with Widgets",
        "content": "Widgets are the core building block of our platform. To create a widget, navigate to the dashboard and click New Widget.",
        "category": "tutorial"
      },
      {
        "id": "doc-2",
        "title": "Widget API Reference",
        "content": "The Widget API supports CRUD operations. Use POST /widgets to create a new widget with a name and configuration object.",
        "category": "reference"
      },
      {
        "id": "doc-3",
        "title": "Troubleshooting Widget Errors",
        "content": "If a widget fails to render, check that the configuration object includes a valid template_id. Common error: WIDGET_TEMPLATE_NOT_FOUND.",
        "category": "troubleshooting"
      }
    ],
    "schema": {
      "title": { "type": "string", "is_searchable": true },
      "content": { "type": "string", "is_searchable": true },
      "category": { "type": "string", "is_filterable": true }
    }
  }'
Response
{
  "documents_upserted": 3
}
You can upload up to 10,000 documents per request. The schema field defines which attributes are searchable (full-text indexed) and filterable. See the Schema guide for the full reference. Search with natural language. Provide an objective (one sentence describing what you’re looking for) and context (a detailed description of your query):
curl -X POST https://api.withcharcoal.com/v1/namespaces/my-docs/search \
  -H "Authorization: Bearer $CHARCOAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "objective": "Fix a widget rendering error",
    "context": "A widget is failing to render and showing WIDGET_TEMPLATE_NOT_FOUND. I need to understand what causes this and how to fix it."
  }'
Response
{
  "session_id": "sess_abc123",
  "status": "completed",
  "documents_scanned": 3,
  "queries_executed": 2,
  "synthesis": "The WIDGET_TEMPLATE_NOT_FOUND error occurs when the widget configuration object is missing a valid template_id. Check that your configuration includes a template_id that corresponds to an existing template.",
  "results": [
    {
      "finding": "Widget rendering failures are caused by missing or invalid template_id in the configuration object",
      "id": "doc-3",
      "excerpts": [
        "If a widget fails to render, check that the configuration object includes a valid template_id. Common error: WIDGET_TEMPLATE_NOT_FOUND."
      ]
    }
  ]
}

Streaming

For real-time progress updates, set stream: true to receive server-sent events:
curl -X POST https://api.withcharcoal.com/v1/namespaces/my-docs/search \
  -H "Authorization: Bearer $CHARCOAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "objective": "Fix a widget rendering error",
    "context": "A widget is failing to render and showing WIDGET_TEMPLATE_NOT_FOUND.",
    "stream": true
  }'
event: status
data: {"message": "Searching documents..."}

event: status
data: {"message": "Analyzing 3 documents..."}

event: session_result
data: {"session_id": "sess_abc123", "status": "completed", "synthesis": "...", "results": [...]}
See Search for the full details on streaming, filters, and multi-turn sessions. Narrow results using attribute filters on fields marked is_filterable:
curl -X POST https://api.withcharcoal.com/v1/namespaces/my-docs/search \
  -H "Authorization: Bearer $CHARCOAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "objective": "Find tutorial content",
    "context": "Show me all tutorial documents.",
    "filters": {"category": "tutorial"}
  }'
See the Filters guide for the full filter syntax.

Next steps

Namespaces & Documents

How documents are organized and schematized.

Search

Streaming, multi-turn sessions, and the search lifecycle.

CLI

Manage Charcoal from your terminal.

API Reference

Full endpoint documentation.