import requests
url = "https://api.hydradb.com/tenants/create"
payload = {
"tenant_id": "tenant_1234",
"is_embeddings_tenant": True,
"embeddings_dimension": 1536,
"tenant_metadata_schema": [
{
"data_type": "VARCHAR",
"enable_match": True,
"max_length": 256,
"name": "category"
},
{
"data_type": "VARCHAR",
"enable_dense_embedding": True,
"enable_sparse_embedding": True,
"max_length": 4096,
"name": "product_description"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
tenant_id: 'tenant_1234',
is_embeddings_tenant: true,
embeddings_dimension: 1536,
tenant_metadata_schema: [
{data_type: 'VARCHAR', enable_match: true, max_length: 256, name: 'category'},
{
data_type: 'VARCHAR',
enable_dense_embedding: true,
enable_sparse_embedding: true,
max_length: 4096,
name: 'product_description'
}
]
})
};
fetch('https://api.hydradb.com/tenants/create', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));curl --request POST \
--url https://api.hydradb.com/tenants/create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tenant_id": "tenant_1234",
"is_embeddings_tenant": true,
"embeddings_dimension": 1536,
"tenant_metadata_schema": [
{
"data_type": "VARCHAR",
"enable_match": true,
"max_length": 256,
"name": "category"
},
{
"data_type": "VARCHAR",
"enable_dense_embedding": true,
"enable_sparse_embedding": true,
"max_length": 4096,
"name": "product_description"
}
]
}
'{
"tenant_id": "tenant_1234",
"status": "accepted",
"message": "Tenant creation started in the background. Use GET /tenants/infra/status?tenant_id=... to check progress."
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}Create Tenant
Create an isolated workspace for your data.
import requests
url = "https://api.hydradb.com/tenants/create"
payload = {
"tenant_id": "tenant_1234",
"is_embeddings_tenant": True,
"embeddings_dimension": 1536,
"tenant_metadata_schema": [
{
"data_type": "VARCHAR",
"enable_match": True,
"max_length": 256,
"name": "category"
},
{
"data_type": "VARCHAR",
"enable_dense_embedding": True,
"enable_sparse_embedding": True,
"max_length": 4096,
"name": "product_description"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
tenant_id: 'tenant_1234',
is_embeddings_tenant: true,
embeddings_dimension: 1536,
tenant_metadata_schema: [
{data_type: 'VARCHAR', enable_match: true, max_length: 256, name: 'category'},
{
data_type: 'VARCHAR',
enable_dense_embedding: true,
enable_sparse_embedding: true,
max_length: 4096,
name: 'product_description'
}
]
})
};
fetch('https://api.hydradb.com/tenants/create', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));curl --request POST \
--url https://api.hydradb.com/tenants/create \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tenant_id": "tenant_1234",
"is_embeddings_tenant": true,
"embeddings_dimension": 1536,
"tenant_metadata_schema": [
{
"data_type": "VARCHAR",
"enable_match": true,
"max_length": 256,
"name": "category"
},
{
"data_type": "VARCHAR",
"enable_dense_embedding": true,
"enable_sparse_embedding": true,
"max_length": 4096,
"name": "product_description"
}
]
}
'{
"tenant_id": "tenant_1234",
"status": "accepted",
"message": "Tenant creation started in the background. Use GET /tenants/infra/status?tenant_id=... to check progress."
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}{
"detail": {
"success": true,
"message": "Error occurred",
"error_code": "<string>"
}
}When to use it
Creating a new tenant is the first step before any ingestion or recall. A tenant is a fully isolated workspace – no tenant can read another tenant’s data. In most cases, you create one tenant per organization. For per-user isolation (B2C), you use sub-tenants inside a single tenant.Endpoint
- Auth: Bearer token
- Idempotency: Re-sending with the same
tenant_idreturns409 CONFLICT - Async: Yes – returns
status: accepted. Poll/tenants/infra/statusbefore use.
Example
curl -X POST 'https://api.hydradb.com/tenants/create' \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "my_first_tenant",
"tenant_metadata_schema": [
{
"name": "category",
"data_type": "VARCHAR",
"max_length": 256,
"enable_match": true
},
{
"name": "product_description",
"data_type": "VARCHAR",
"max_length": 4096,
"enable_dense_embedding": true,
"enable_sparse_embedding": true
}
]
}'
const response = await client.tenant.create({
tenant_id: "my_first_tenant",
tenant_metadata_schema: [
{
name: "category",
data_type: "VARCHAR",
max_length: 256,
enable_match: true
},
{
name: "product_description",
data_type: "VARCHAR",
max_length: 4096,
enable_dense_embedding: true,
enable_sparse_embedding: true
}
]
});
response = client.tenant.create(
tenant_id="my_first_tenant",
tenant_metadata_schema={
"category": "string",
"product_description": "string",
},
)
Request parameters
| Name | Type | Required | Description |
|---|---|---|---|
tenant_id | string | Yes | Unique identifier for the tenant. |
tenant_metadata_schema | array (TypeScript) / object (Python) | No | Defines tenant-level metadata fields. See Metadata schema below. |
Response
{
"status": "accepted",
"tenant_id": "my_first_tenant",
"message": "Tenant creation started in the background. Use GET /tenants/infra/status?tenant_id=... to check progress."
}
| Field | Description |
|---|---|
status | Always accepted. Provisioning runs in the background. |
tenant_id | The tenant identifier provided in the request. |
message | Human-readable next-step hint. |
Metadata schema
tenant_metadata_schema defines fields that all documents in the tenant inherit. Each entry has:
| Field | Type | Default | Description |
|---|---|---|---|
name | string | – | The field name. Required. |
data_type | enum | VARCHAR | Milvus data type. See list below. |
max_length | integer | 1024 | Max length for VARCHAR fields. |
enable_match | boolean | false | Enable exact-match filtering on this field. |
enable_dense_embedding | boolean | false | Create a dense embedding for semantic similarity search. Only applicable to VARCHAR fields. |
enable_sparse_embedding | boolean | false | Create a sparse embedding (BM25) for keyword search. Only applicable to VARCHAR fields. |
nullable | boolean | true | Whether the field can be null. |
data_type values:
BOOL, INT8, INT16, INT32, INT64, FLOAT, DOUBLE, VARCHAR, JSON, FLOAT_VECTOR, SPARSE_FLOAT_VECTOR. ARRAY is not supported and is rejected with 400; for multi-value fields declare VARCHAR and store the values comma-joined.
For text fields that need to be semantically searchable, use VARCHAR with enable_dense_embedding: true. For keyword (BM25) searchability, add enable_sparse_embedding: true. For fields that must be filterable via metadata_filters, use enable_match: true. These flags are independent and can be combined.
additional_metadata fields per document at ingestion time, but tenant-level fields cannot be renamed or removed. Plan the schema carefully before creating the tenant.Metadata schema examples
The following patterns cover the most common shapes oftenant_metadata_schema. Each example shows only the schema entries – wrap them in a full POST /tenants/create request like the Example above.
Single exact-match filter field
The minimum useful schema field for deterministic filtering with metadata_filters is a VARCHAR field with enable_match: true.
{
"tenant_metadata_schema": [
{
"name": "environment",
"data_type": "VARCHAR",
"enable_match": true
}
]
}
metadata.environment at ingestion time can then be filtered exactly during recall:
{
"metadata_filters": {
"environment": "production"
}
}
enable_match fields
Applications commonly define several stable fields they expect to filter on via metadata_filters. Use INT32, INT64, BOOL, FLOAT, or other typed fields when the value is not a string. Every field that must be filterable requires enable_match: true.
{
"tenant_metadata_schema": [
{
"name": "environment",
"data_type": "VARCHAR",
"enable_match": true
},
{
"name": "document_type",
"data_type": "VARCHAR",
"enable_match": true
},
{
"name": "version",
"data_type": "INT32",
"enable_match": true
},
{
"name": "is_published",
"data_type": "BOOL",
"enable_match": true
}
]
}
metadata_filters, they combine as structured exact-match constraints – a chunk must satisfy every key to remain a candidate.
Long VARCHAR field
VARCHAR defaults to a max_length of 1024 characters. For longer structured string values – compound identifiers, full label strings, or composite tags – set max_length explicitly.
{
"name": "compliance_label",
"data_type": "VARCHAR",
"max_length": 4096,
"enable_match": true
}
enable_match vs no flag
Only fields declared with enable_match: true are usable in metadata_filters for deterministic filtering. A field without enable_match: true can still be stored in the schema, but passing it as a metadata_filters key will have no effect.
{
"tenant_metadata_schema": [
{
"name": "region",
"data_type": "VARCHAR",
"enable_match": true
},
{
"name": "internal_notes",
"data_type": "VARCHAR"
}
]
}
regionhasenable_match: trueand can be used inmetadata_filters.internal_noteshas noenable_match, so it cannot be used inmetadata_filters. It is stored but not filterable.- For free-form display or bookkeeping fields that do not need filtering, prefer
additional_metadataat ingestion time rather than adding them to the tenant schema.
enable_dense_embedding and enable_sparse_embedding fields
enable_dense_embedding makes a field semantically searchable (dense vector). enable_sparse_embedding makes it keyword-searchable (BM25/sparse vector). Use these when the field itself is a body of text you want included in semantic or keyword recall, for example a product_description that should be retrieved alongside the document.
{
"name": "product_description",
"data_type": "VARCHAR",
"max_length": 4096,
"enable_dense_embedding": true,
"enable_sparse_embedding": true
}
- Use
enable_match: truefor fields you intend to filter on exactly viametadata_filters. - Use
enable_dense_embedding/enable_sparse_embeddingforVARCHARfields that should be searchable as text. - These flags are independent: an embedding-enabled field is not automatically usable as a
metadata_filterskey.
Behavior notes
GET /tenants/infra/status?tenant_id=... before your first ingestion call. Both values in vectorstore_status and graph_status must be true before the tenant is ready.sub_tenant_id targets this default. See Essentials → Multi-Tenant for details.Related endpoints
- Next: Check infra status – poll until provisioning completes
- Next: Upload knowledge – start ingesting data
- Related: Delete tenant – teardown
Errors
Common codes:400 INVALID_PARAMETERS, 409 TENANT_ALREADY_EXISTS, 422 VALIDATION_ERROR. See Error Responses for the full list.
Read more: Essentials → Multi-Tenant Support · Essentials → MetadataAuthorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
Request model for creating a tenant with optional metadata schema.
The tenant_metadata_schema allows you to define custom fields that will be indexed in Milvus with configurable search capabilities.
Example:
{
"tenant_id": "my-tenant",
"tenant_metadata_schema": [
{
"name": "category",
"data_type": "VARCHAR",
"max_length": 256,
"enable_match": true
},
{
"name": "product_description",
"data_type": "VARCHAR",
"max_length": 4096,
"enable_dense_embedding": true,
"enable_sparse_embedding": true
}
]
}
Unique tenant identifier
1"tenant_1234"
True to create embeddings tenant
true
Embedding dimensions for embeddings tenant. Not required for non-embeddings (is_embeddings_tenant=False) tenants
Schema definition for tenant metadata fields. Each field can be configured for: filtering (enable_match), semantic search (enable_dense_embedding), and/or keyword search (enable_sparse_embedding). Fields with embeddings enabled must be VARCHAR type.
Show child attributes
Show child attributes
[
{
"data_type": "VARCHAR",
"enable_match": true,
"max_length": 256,
"name": "category"
},
{
"data_type": "VARCHAR",
"enable_dense_embedding": true,
"enable_sparse_embedding": true,
"max_length": 4096,
"name": "product_description"
}
]
Response
Successful Response
Response when tenant creation is accepted and runs in the background.
Was this page helpful?
