Databases
A high-performance document database built on OpenSearch. Supports schema definition, CRUD, full-text search, and vector search.
Key Features
- Schema definition: field types, indexing options, vector field configuration
- CRUD operations: single/bulk document create, read, update, delete
- Full-text search: OpenSearch Query DSL support (match, term, bool, range)
- Vector search: k-NN semantic search (Pro plan and above)
- Aggregations: terms, date_histogram, statistical aggregations
Credit Costs
Database operations deduct credits by type. Credits are automatically refunded if an operation fails.
| Operation | Endpoint | Credits |
|---|---|---|
| Create document | POST /documents | 0.1 |
| Get document | GET /documents/{id} | 0.05 |
| Update document | PUT, PATCH /documents/{id} | 0.1 |
| Delete document | DELETE /documents/{id} | 0.05 |
| Bulk create | POST /documents/_bulk | 5.0 / 100 docs |
| Bulk delete | POST /documents/_bulk_delete | 0.05 / doc |
| Bulk update | POST /documents/_bulk_update | 0.1 / doc |
| Full-text search | POST /search | 0.5 |
| Aggregation | POST /aggregate | 1.0 |
| Vector search | POST /search/vector | 2.0 |
Free: Database create/delete, list, schema changes, stats, document listing, and document count (_count) do not deduct credits.
Plan Limits
Database resource limits vary by subscription plan.
| Item | Free | Pro | Team | Enterprise |
|---|---|---|---|---|
| Max databases | 1 | 5 | 20 | 1,000 |
| Max documents per DB | 10,000 | 500,000 | 5,000,000 | 100,000,000 |
| Max storage | 100 MB | 5 GB | 50 GB | 500 GB |
| Max document size | 100 KB | 1 MB | 10 MB | 100 MB |
| Max bulk operation size | 100 | 1,000 | 10,000 | 100,000 |
| Vector search | - | 1,536 dims | 2,048 dims | 4,096 dims |
Create a Database
Create a new database with a schema. The database name must be unique within the team.
Naming Rules
- Must start with a lowercase letter
- Only lowercase letters, digits, hyphens (
-), and underscores (_) are allowed - 3–50 characters
aiapi_,db_system_,_cannot be used as a prefix (reserved prefixes)
curl -X POST https://api.core.today/v1/databases \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "products",
"display_name": "Product Catalog",
"description": "E-commerce product database",
"schema_fields": {
"title": {"type": "text", "index": true},
"description": {"type": "text", "index": true},
"price": {"type": "float"},
"category": {"type": "keyword"},
"tags": {"type": "keyword"},
"in_stock": {"type": "boolean"},
"created_at": {"type": "date"}
}
}'Example Response
{
"database_uid": "db_abc123",
"name": "products",
"display_name": "Product Catalog",
"description": "E-commerce product database",
"team_id": "team_xyz",
"schema_fields": {...},
"document_count": 0,
"created_at": "2024-12-26T10:00:00Z"
}Supported Field Types
| Type | Description | Example |
|---|---|---|
text | Full-text searchable text | "Product description..." |
keyword | String for exact matching (filters, aggregations) | "electronics" |
integer | Integer | 42 |
long | 64-bit integer | 9223372036854775807 |
float | 32-bit floating point | 19.99 |
double | 64-bit floating point | 3.141592653589793 |
boolean | true/false | true |
date | ISO 8601 date | "2024-12-26T10:00:00Z" |
object | Nested object (indexing can be turned on/off) | {"key": "value"} |
nested | Array of independently queryable objects | [{"name": "A"}, ...] |
knn_vector | Embedding for vector search (Pro+) | [0.1, 0.2, ...] |
Vector Field Configuration
A field for vector search must specify dimension and space_type:
"embedding": {
"type": "knn_vector",
"dimension": 1536,
"space_type": "cosinesimil"
}Document CRUD
Automatic Metadata (_meta)
Every document automatically gets a _meta field:
_meta.created_at— document creation time (ISO 8601)_meta.updated_at— last update time (ISO 8601)_meta.created_by_api_key— UID of the API key used to create it
Create Document
docs.databases.crud.createCodeBulk Create Documents
curl -X POST https://api.core.today/v1/databases/{database_uid}/documents/_bulk \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{"id": "product-001", "data": {"title": "Product 1", "price": 99.99}},
{"id": "product-002", "data": {"title": "Product 2", "price": 149.99}},
{"id": "product-003", "data": {"title": "Product 3", "price": 199.99}}
]
}'Response: Returns the success/failure counts and error details.
Get Document
# Get a specific document
curl https://api.core.today/v1/databases/{database_uid}/documents/{doc_id} \
-H "X-API-Key: cdt_your_api_key"
# Get specific fields only (Field Projection)
curl "https://api.core.today/v1/databases/{database_uid}/documents/{doc_id}?_source=title,price" \
-H "X-API-Key: cdt_your_api_key"
# List documents (pagination)
curl "https://api.core.today/v1/databases/{database_uid}/documents?size=20&from=0" \
-H "X-API-Key: cdt_your_api_key"
# List documents - specific fields only
curl "https://api.core.today/v1/databases/{database_uid}/documents?size=20&_source=title,price" \
-H "X-API-Key: cdt_your_api_key"_source: Specify a comma-separated list of fields to include only those in the response. Omit it to return all fields.
Update Document
docs.databases.crud.updateCodeDelete Document
curl -X DELETE https://api.core.today/v1/databases/{database_uid}/documents/{doc_id} \
-H "X-API-Key: cdt_your_api_key"Bulk Delete
curl -X POST https://api.core.today/v1/databases/{database_uid}/documents/_bulk_delete \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"ids": ["product-001", "product-002", "product-003"]
}'Credits: 0.05 × document count. Non-existent IDs are reported as errors.
Bulk Update
curl -X POST https://api.core.today/v1/databases/{database_uid}/documents/_bulk_update \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{"id": "product-001", "data": {"price": 179.99, "in_stock": false}},
{"id": "product-002", "data": {"price": 129.99}},
{"id": "product-003", "data": {"category": "accessories"}}
]
}'Credits: 0.1 × document count. Behaves as a partial update (PATCH); only the specified fields are updated.
Document Count
# Total document count
curl https://api.core.today/v1/databases/{database_uid}/documents/_count \
-H "X-API-Key: cdt_your_api_key"
# Conditional count (pass JSON via the query parameter)
curl "https://api.core.today/v1/databases/{database_uid}/documents/_count?q=%7B%22term%22%3A%7B%22category%22%3A%22electronics%22%7D%7D" \
-H "X-API-Key: cdt_your_api_key"Free: No credits are deducted. Response: {"count": 1234}
Exclude Fields (_source_excludes)
You can exclude specific fields from the response. _source when used together, is converted into includes/excludes.
docs.databases.crud.excludeCodeSearch
Provides powerful search using the OpenSearch Query DSL.
Full-text Search
curl -X POST https://api.core.today/v1/databases/{database_uid}/search \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"query": {
"match": {
"description": "wireless headphones"
}
},
"size": 10,
"from": 0,
"_source": ["title", "price", "category"]
}'_source: The list of fields to include in the response. Omit it to return all fields.
Compound Search (Boolean Query)
{
"query": {
"bool": {
"must": [
{"match": {"description": "headphones"}}
],
"filter": [
{"term": {"category": "electronics"}},
{"range": {"price": {"gte": 100, "lte": 300}}}
],
"should": [
{"term": {"in_stock": true}}
]
}
},
"sort": [
{"price": {"order": "asc"}}
],
"highlight": {
"fields": {"description": {}}
}
}Deep Pagination (search_after)
from + size exceeds 10,000, you must use search_after. Pass the last sort value of the previous result to fetch the next page.
{
"query": {"match_all": {}},
"sort": [
{"_meta.created_at": {"order": "desc"}},
{"_id": {"order": "asc"}}
],
"size": 100,
"search_after": ["2025-01-01T00:00:00Z", "product-500"]
}Note: search_after When using it, you must specify sort, and it is recommended to include _id as a tie-breaker.
Search Response Example
{
"total": 42,
"hits": [
{
"id": "product-001",
"score": 1.5,
"data": {
"title": "Wireless Headphones",
"price": 199.99,
...
},
"highlight": {
"description": ["High-quality <em>wireless</em> <em>headphones</em>..."]
}
}
]
}Vector Search (k-NN)
Pro+Semantic similarity search using embedding vectors. You can store and search text/image embeddings generated by AI models.
Schema with a Vector Field
{
"name": "articles",
"schema_fields": {
"title": {"type": "text"},
"content": {"type": "text"},
"embedding": {
"type": "knn_vector",
"dimension": 1536,
"space_type": "cosinesimil"
}
}
}Vector Search Request
curl -X POST https://api.core.today/v1/databases/{database_uid}/search/vector \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"field": "embedding",
"vector": [0.1, 0.2, 0.3, ...],
"k": 10,
"filter": {
"term": {"category": "technology"}
},
"_source": ["title", "content"]
}'Embedding Tips
OpenAI's text-embedding-3-small (1536 dims) or Cohere's embedding models can convert text into vectors. Generate embeddings via the LLM API and store them in the database.
Aggregations
Provides aggregation features for data analysis.
curl -X POST https://api.core.today/v1/databases/{database_uid}/aggregate \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"query": {"match_all": {}},
"aggregations": {
"by_category": {
"terms": {"field": "category", "size": 10}
},
"avg_price": {
"avg": {"field": "price"}
},
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{"to": 100},
{"from": 100, "to": 200},
{"from": 200}
]
}
}
}
}'Aggregation Response Example
{
"total": 1000,
"aggregations": {
"by_category": {
"buckets": [
{"key": "electronics", "doc_count": 350},
{"key": "clothing", "doc_count": 280},
...
]
},
"avg_price": {"value": 149.99},
"price_ranges": {
"buckets": [
{"key": "*-100.0", "doc_count": 200},
{"key": "100.0-200.0", "doc_count": 500},
{"key": "200.0-*", "doc_count": 300}
]
}
}
}Database Management
List Databases
curl https://api.core.today/v1/databases \
-H "X-API-Key: cdt_your_api_key"Add Fields
You can add new fields to an existing database. The type of existing fields cannot be changed.
curl -X POST https://api.core.today/v1/databases/{database_uid}/fields \
-H "X-API-Key: cdt_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"rating": {"type": "float"},
"reviews_count": {"type": "integer"}
}
}'Get Stats
curl https://api.core.today/v1/databases/{database_uid}/stats \
-H "X-API-Key: cdt_your_api_key"Delete Database
Warning: Deleting a database is irreversible. All documents are permanently deleted.
curl -X DELETE https://api.core.today/v1/databases/{database_uid} \
-H "X-API-Key: cdt_your_api_key"Field Value Autocomplete (Suggest)
keyword type field values via autocomplete.
curl "https://api.core.today/v1/databases/{database_uid}/suggest?field=category&prefix=ele&limit=10" \
-H "X-API-Key: cdt_your_api_key"
# Response: {"suggestions": ["electronics", "electric-vehicles", ...]}Free: No credits are deducted.
Saved Queries
You can save and manage frequently used search queries. All free.
docs.databases.mgmt.queriesCodeSDK Examples
JavaScript / TypeScript
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.core.today/v1',
headers: { 'X-API-Key': 'cdt_your_api_key' }
});
// Create a document
const doc = await api.post('/databases/db_abc123/documents', {
id: 'product-001',
data: { title: 'My Product', price: 99.99 }
});
// Search
const results = await api.post('/databases/db_abc123/search', {
query: { match: { title: 'product' } },
size: 10
});
console.log(results.data.hits);Python
import requests
API_KEY = "cdt_your_api_key"
BASE_URL = "https://api.core.today/v1"
headers = {"X-API-Key": API_KEY}
# Create a document
response = requests.post(
f"{BASE_URL}/databases/db_abc123/documents",
headers=headers,
json={
"id": "product-001",
"data": {"title": "My Product", "price": 99.99}
}
)
# Search
results = requests.post(
f"{BASE_URL}/databases/db_abc123/search",
headers=headers,
json={
"query": {"match": {"title": "product"}},
"size": 10
}
)
for hit in results.json()["hits"]:
print(hit["data"]["title"])Error Responses
When a request fails, the following error responses are returned. If an operation that deducted credits fails, the credits are automatically refunded.
402 — Insufficient Credits
{
"detail": "Insufficient credits. Required: 0.50, Available: 0.12"
}404 — Database or Document Not Found
{
"detail": "Database not found"
}
// or
{
"detail": "Document not found"
}400 — Validation Failed
{
"detail": "Database with name 'products' already exists"
}
// or
{
"detail": "Invalid query: Query type 'script' is not allowed"
}
// or
{
"detail": "Pagination limit exceeded: from (9990) + size (20) = 10010 exceeds maximum of 10000. Use search_after for deep pagination."
}403 — Plan Limit
{
"detail": "Vector search is not available in your plan"
}
// or
{
"detail": "Maximum number of databases (1) reached for your plan"
}Reseller: Per-customer Data Isolation
When a team with reseller mode enabled sends an X-Customer-Id header to the public document endpoints, all document reads/writes/searches within a single database are automatically isolated to that end-customer. You do not need to create a separate DB per customer.
How It Works
- Writes: On create/bulk-create/update, the document is automatically tagged with that customer.
- Reads & search: Get/search/count/vector search are automatically filtered to that customer's documents.
- Cross-access blocked: Getting/deleting another customer's document returns
404(existence is not revealed either). - Without the header: for reseller teams the request is rejected with 400 (customer_scope_required) — isolation never silently turns off. To manage the entire dataset directly, send an explicit X-Customer-Scope: all header. Non-reseller teams are unaffected.
Applicable endpoints: /databases/{uid}/documents (and /_bulk), /documents/{doc_id}, /documents/_count, /search, /search/vector.
Isolation guarantee: One customer's data is never exposed to another. If a non-reseller team sends this header, it is ignored.
Reserved field prefix _ — differs from the naming rule
Document field names starting with an underscore (_) are system-reserved and are automatically stripped from the document body (so internal fields such as the customer tag cannot be spoofed). This is a database name prefix rule (forbidding aiapi_, db_system_, _ as the start of a DB name) described earlier, but a different rule. The former applies to a document's field keys, the latter to the DB's name.
Example — same DB, two customers' document sets isolated from each other
docs.databases.reseller.exampleCodeBest Practices
- Schema design: Use the
keywordtype for fields frequently used in search, and thetexttype for fields that need full-text search. - Bulk operations: When processing multiple documents, use the
/_bulkendpoints. - Pagination:
from + sizecan go up to 10,000. Beyond that, usesearch_aftertogether withsort. - Filter vs query: Put exact value matching in
filter, and searches that need scoring inquery. - Vector search: Set the vector dimension to match your embedding model; using it together with filters is more efficient.