Update Metadata

Update custom metadata fields for a knowledge item. This endpoint allows you to add, update, or remove custom metadata properties while keeping the content and reserved fields unchanged.

Endpoint

PUT /v1/workspaces/{workspaceId}/knowledge/{knowledgeId}/metadata

Authentication

This endpoint requires a Bearer token obtained through the two-step authentication flow:

  1. First, generate an access token using your API key
  2. Use that access token in the Authorization header

See Authentication for the complete authentication flow.

Path Parameters

ParameterTypeRequiredDescription
workspaceIdstring (UUID)YesThe ID of your workspace
knowledgeIdstring (UUID)YesThe ID of the knowledge item to update

Request Body

FieldTypeRequiredDescription
typestringYesKnowledge type: URL, FILE, LINK, STRING, WEBSITE, or ELASTICSEARCH_INDEX. Must match the item's actual type.
metadataobjectYesCustom metadata as key-value pairs. Values must be strings or numbers only.
removeMetadataKeysarray of stringsNoArray of metadata keys to remove

Metadata Value Constraints

Important: Metadata values can only be strings or numbers. Nested objects, arrays, booleans, or null values are not allowed.

// Valid metadata
{
  "metadata": {
    "department": "Engineering",
    "version": "2.0",
    "priority": 5,
    "reviewedBy": "John Doe"
  }
}
 
// Invalid metadata - will be rejected
{
  "metadata": {
    "settings": {"nested": "object"},  // ❌ No nested objects
    "tags": ["tag1", "tag2"],           // ❌ No arrays
    "active": true,                      // ❌ No booleans
    "deletedAt": null                    // ❌ No null values
  }
}

Reserved Field Restrictions

The following fields cannot be updated via this endpoint:

Attempting to update these fields will result in an error.

Response

Success Response

Status Code: 200 OK

Headers:

X-API-Version: v1

Body:

{
  "knowledgeId": "550e8400-e29b-41d4-a716-446655440000"
}

Examples

Add Custom Metadata

Add custom metadata fields to a knowledge item:

# Step 1: Generate access token (do this once, reuse for multiple requests)
ACCESS_TOKEN=$(curl -s -X POST \
  'https://api.sharely.ai/workspaces/your-workspace-id/generate-access-key-token' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: sk-sharely-your-api-key' \
  -d '{}' | jq -r '.token')
 
# Step 2: Update metadata using the access token
curl -X PUT \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/123e4567-e89b-12d3-a456-426614174000/metadata' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'organizationid: your-organization-id' \
  -d '{
    "type": "FILE",
    "metadata": {
      "department": "Engineering",
      "version": "2.1",
      "reviewedBy": "Jane Doe",
      "priority": 3
    }
  }'

Response:

{
  "knowledgeId": "123e4567-e89b-12d3-a456-426614174000"
}

Update Existing Metadata

Update specific metadata fields while preserving others:

# Using the access token from Step 1 above
curl -X PUT \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/123e4567-e89b-12d3-a456-426614174000/metadata' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'organizationid: your-organization-id' \
  -d '{
    "type": "FILE",
    "metadata": {
      "version": "2.2",
      "lastUpdated": "2025-01-16"
    }
  }'

Remove Metadata Fields

Remove specific metadata fields using removeMetadataKeys:

# Using the access token from Step 1 above
curl -X PUT \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/123e4567-e89b-12d3-a456-426614174000/metadata' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'organizationid: your-organization-id' \
  -d '{
    "type": "FILE",
    "metadata": {},
    "removeMetadataKeys": ["oldField", "deprecatedField"]
  }'

Add and Remove Metadata Simultaneously

You can add new metadata and remove old fields in a single request:

# Using the access token from Step 1 above
curl -X PUT \
  'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/123e4567-e89b-12d3-a456-426614174000/metadata' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'organizationid: your-organization-id' \
  -d '{
    "type": "URL",
    "metadata": {
      "category": "Documentation",
      "updatedAt": "2025-01-16"
    },
    "removeMetadataKeys": ["oldCategory", "tempField"]
  }'

JavaScript Example

const API_KEY = 'sk-sharely-your-api-key';
const WORKSPACE_ID = 'your-workspace-id';
const ORGANIZATION_ID = 'your-organization-id';
const API_BASE_URL = 'https://api.sharely.ai';
 
// Step 1: Generate access token
async function getAccessToken() {
  const response = await fetch(
    `${API_BASE_URL}/workspaces/${WORKSPACE_ID}/generate-access-key-token`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': API_KEY
      },
      body: JSON.stringify({})
    }
  );
  const data = await response.json();
  return data.token;
}
 
// Step 2: Update metadata
async function updateMetadata(accessToken, knowledgeId, type, metadata, removeKeys = null) {
  const body = {
    type: type,
    metadata: metadata
  };
 
  if (removeKeys && removeKeys.length > 0) {
    body.removeMetadataKeys = removeKeys;
  }
 
  const response = await fetch(
    `${API_BASE_URL}/v1/workspaces/${WORKSPACE_ID}/knowledge/${knowledgeId}/metadata`,
    {
      method: 'PUT',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
        'organizationid': ORGANIZATION_ID
      },
      body: JSON.stringify(body)
    }
  );
 
  if (!response.ok) {
    throw new Error(`Update failed: ${response.statusText}`);
  }
 
  return await response.json();
}
 
// Usage - Add metadata
const accessToken = await getAccessToken();
try {
  const result = await updateMetadata(
    accessToken,
    '123e4567-e89b-12d3-a456-426614174000',
    'FILE',
    {
      department: 'Engineering',
      version: '2.1',
      priority: 5
    }
  );
  console.log('Metadata updated:', result.knowledgeId);
} catch (error) {
  console.error('Update failed:', error.message);
}
 
// Usage - Add and remove metadata
try {
  const result = await updateMetadata(
    accessToken,
    '123e4567-e89b-12d3-a456-426614174000',
    'FILE',
    {
      newField: 'newValue',
      updatedAt: '2025-01-16'
    },
    ['oldField', 'deprecatedField']
  );
  console.log('Metadata updated:', result.knowledgeId);
} catch (error) {
  console.error('Update failed:', error.message);
}

Python Example

import requests
 
API_KEY = 'sk-sharely-your-api-key'
WORKSPACE_ID = 'your-workspace-id'
ORGANIZATION_ID = 'your-organization-id'
API_BASE_URL = 'https://api.sharely.ai'
 
# Step 1: Generate access token
def get_access_token():
    response = requests.post(
        f'{API_BASE_URL}/workspaces/{WORKSPACE_ID}/generate-access-key-token',
        headers={
            'Content-Type': 'application/json',
            'x-api-key': API_KEY
        },
        json={}
    )
    response.raise_for_status()
    return response.json()['token']
 
# Step 2: Update metadata
def update_metadata(access_token, knowledge_id, knowledge_type, metadata, remove_keys=None):
    payload = {
        'type': knowledge_type,
        'metadata': metadata
    }
 
    if remove_keys:
        payload['removeMetadataKeys'] = remove_keys
 
    response = requests.put(
        f'{API_BASE_URL}/v1/workspaces/{WORKSPACE_ID}/knowledge/{knowledge_id}/metadata',
        headers={
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json',
            'organizationid': ORGANIZATION_ID
        },
        json=payload
    )
 
    response.raise_for_status()
    return response.json()
 
# Usage - Add metadata
access_token = get_access_token()
try:
    result = update_metadata(
        access_token,
        '123e4567-e89b-12d3-a456-426614174000',
        'FILE',
        {
            'department': 'Engineering',
            'version': '2.1',
            'priority': 5
        }
    )
    print(f"Metadata updated: {result['knowledgeId']}")
except requests.exceptions.HTTPError as error:
    print(f"Update failed: {error}")
 
# Usage - Add and remove metadata
try:
    result = update_metadata(
        access_token,
        '123e4567-e89b-12d3-a456-426614174000',
        'FILE',
        {
            'newField': 'newValue',
            'updatedAt': '2025-01-16'
        },
        ['oldField', 'deprecatedField']
    )
    print(f"Metadata updated: {result['knowledgeId']}")
except requests.exceptions.HTTPError as error:
    print(f"Update failed: {error}")

Error Responses

400 Bad Request

Missing required fields:

{
  "error": "Bad Request",
  "message": "Missing required field: metadata"
}

Invalid metadata values (nested objects):

{
  "error": "Bad Request",
  "message": "Metadata values must be strings or numbers only, nested objects are not allowed"
}

Attempting to update reserved fields:

{
  "error": "Bad Request",
  "message": "Title cannot be updated with this endpoint, use the reserved fields endpoint"
}
{
  "error": "Bad Request",
  "message": "Language cannot be updated with this endpoint, use the reserved fields endpoint"
}

401 Unauthorized

Invalid or missing API key:

{
  "error": "Unauthorized",
  "message": "Invalid or missing API key"
}

403 Forbidden

Knowledge not in completed status:

{
  "error": "Forbidden",
  "message": "Knowledge with ID {knowledgeId} is not in completed status"
}

404 Not Found

Knowledge item doesn't exist:

{
  "error": "Not Found",
  "message": "Knowledge with ID {knowledgeId} not found"
}

422 Unprocessable Entity

Type mismatch:

{
  "error": "Unprocessable Entity",
  "message": "Type mismatch"
}

500 Internal Server Error

Server error during update:

{
  "error": "Internal Server Error",
  "message": "Failed to update metadata"
}

Use Cases

Tag Content by Department

Add organizational metadata to knowledge items:

await updateMetadata(
  knowledgeId,
  'FILE',
  {
    department: 'Sales',
    region: 'North America',
    accessLevel: '2'
  }
);

Track Document Versions

Maintain version tracking in metadata:

await updateMetadata(
  knowledgeId,
  'FILE',
  {
    version: '3.0',
    versionDate: '2025-01-16',
    changedBy: 'Jane Doe'
  }
);

Add Review Information

Track review status and reviewers:

await updateMetadata(
  knowledgeId,
  'URL',
  {
    reviewStatus: 'approved',
    reviewedBy: 'John Smith',
    reviewDate: '2025-01-16',
    nextReviewDate: '2025-04-16'
  }
);

Clean Up Old Metadata

Remove deprecated or temporary metadata fields:

await updateMetadata(
  knowledgeId,
  'FILE',
  {},
  ['tempField', 'deprecatedCategory', 'oldVersion']
);

Batch Update Metadata

Update metadata for multiple knowledge items:

async function batchUpdateMetadata(updates) {
  const results = [];
 
  for (const { knowledgeId, type, metadata } of updates) {
    try {
      const result = await updateMetadata(knowledgeId, type, metadata);
      results.push({ success: true, knowledgeId, result });
    } catch (error) {
      results.push({ success: false, knowledgeId, error: error.message });
    }
  }
 
  return results;
}
 
// Usage
const updates = [
  {
    knowledgeId: 'knowledge-1',
    type: 'FILE',
    metadata: { department: 'Engineering', version: '2.0' }
  },
  {
    knowledgeId: 'knowledge-2',
    type: 'URL',
    metadata: { category: 'Documentation', priority: 5 }
  }
];
 
const results = await batchUpdateMetadata(updates);

Important Notes

Metadata Merging

Metadata is merged with existing metadata, not replaced:

Existing metadata:

{
  "department": "Sales",
  "version": "1.0"
}

Update request:

{
  "metadata": {
    "version": "2.0",
    "priority": 5
  }
}

Result:

{
  "department": "Sales",
  "version": "2.0",
  "priority": 5
}

Type Validation

The type parameter must match the knowledge item's actual type. The API validates this to prevent accidental updates to the wrong item.

Status Requirement

Knowledge items must be in COMPLETED status to update metadata. Items that are still processing cannot be updated.

Reserved Fields

To update title or language, use the Update Reserved Fields endpoint instead. These fields are considered core properties and require special handling.

Vector Database Updates

When you update metadata, the changes are propagated to the vector database (Pinecone) to ensure search results reflect the updated metadata.

Best Practices

Use Consistent Key Names

Establish standard metadata key names across your organization:

// Good - consistent naming
await updateMetadata(knowledgeId, 'FILE', {
  department: 'Engineering',
  reviewedBy: 'Jane Doe',
  reviewDate: '2025-01-16'
});
 
// Avoid - inconsistent naming
await updateMetadata(knowledgeId, 'FILE', {
  dept: 'Engineering',          // Inconsistent abbreviation
  reviewer: 'Jane Doe',          // Different naming pattern
  review_date: '2025-01-16'      // Snake case vs camelCase
});

Validate Type Before Updating

Always verify the knowledge type before updating:

const knowledge = await getKnowledge(knowledgeId);
await updateMetadata(
  knowledgeId,
  knowledge.type,  // Use actual type
  metadata
);

Handle Errors Gracefully

Check for common error conditions:

try {
  await updateMetadata(knowledgeId, 'FILE', metadata);
} catch (error) {
  if (error.status === 403) {
    console.error('Knowledge not in completed status');
  } else if (error.status === 422) {
    console.error('Type mismatch - verify knowledge type');
  } else if (error.status === 400) {
    console.error('Invalid metadata format or reserved field');
  } else {
    console.error('Update failed:', error.message);
  }
}

Remove Metadata Carefully

Verify keys exist before removing:

const knowledge = await getKnowledge(knowledgeId);
const keysToRemove = ['oldField', 'deprecatedField'].filter(key =>
  knowledge.metadata.hasOwnProperty(key)
);
 
if (keysToRemove.length > 0) {
  await updateMetadata(knowledgeId, knowledge.type, {}, keysToRemove);
}

Related Endpoints