Skip to main content

Confidential Entities API

Overview​

The Confidential Entities API provides access to restricted entity information within the Ring Platform. This endpoint is reserved for users with CONFIDENTIAL or ADMIN roles and implements strict security controls to protect sensitive organizational data.

Endpoint Details​

  • URL: /api/confidential/entities
  • Method: GET
  • Authentication: Required (JWT Token)
  • Authorization: CONFIDENTIAL or ADMIN role required
  • Rate Limit: Standard API limits apply
  • Caching: No-cache headers enforced for security

Ring Platform Concepts​

What are Confidential Entities?​

Confidential entities represent organizations with restricted access levels in the Ring Platform:

  • Enhanced Privacy: Only visible to users with appropriate clearance
  • Sensitive Information: May contain classified business data
  • Exclusive Access: Limited to CONFIDENTIAL and ADMIN users
  • High-Value Networks: Premium organizations and institutions
  • Strategic Partnerships: Entities involved in sensitive collaborations

Access Control​

The confidential tier implements strict access controls:

  • Role Verification: CONFIDENTIAL or ADMIN role required
  • Session Validation: Active authentication session mandatory
  • No Caching: Responses are never cached for security
  • Audit Logging: All access attempts are logged

Query Parameters​

ParameterTypeRequiredDefaultDescription
pageintegerNo1Page number for pagination
limitintegerNo20Number of entities per page (max 100)
sortstringNocreatedAt:descSort field and direction (field:asc/desc)
filterstringNo''Filter by entity status
startAfterstringNoundefinedEntity ID for cursor-based pagination

Supported Sort Fields​

  • createdAt - Creation date
  • updatedAt - Last modification date
  • name - Entity name
  • addedBy - Creator user ID
  • status - Entity status

Supported Filters​

  • active - Active entities only
  • pending - Entities pending approval
  • suspended - Temporarily suspended entities
  • archived - Archived entities

Request Format​

Headers​

GET /api/confidential/entities?page=1&limit=20&sort=createdAt:desc
Authorization: Bearer <jwt_token>

Example Request​

GET /api/confidential/entities?page=1&limit=10&sort=name:asc&filter=active
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response Format​

Success Response (200 OK)​

{
"entities": [
{
"id": "entity_confidential_123",
"name": "Strategic Partners Corp",
"description": "High-level strategic partnership organization",
"industryType": "technology",
"foundedYear": 2020,
"employeeCount": "51-200",
"location": "New York, NY",
"isConfidential": true,
"status": "active",
"addedBy": "user_admin_456",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-20T14:45:00Z",
"logoUrl": "https://storage.example.com/logos/strategic-partners.png",
"websiteUrl": "https://strategicpartners.example.com",
"socialLinks": {
"linkedin": "https://linkedin.com/company/strategic-partners",
"twitter": "https://twitter.com/strategicpartners"
},
"certifications": ["ISO-27001", "SOC-2"],
"partnerships": ["entity_789", "entity_321"],
"memberCount": 15,
"opportunityCount": 8
}
],
"lastVisible": "entity_confidential_123",
"totalPages": 5,
"totalEntities": 87
}

Error Responses​

401 Unauthorized​

{
"error": "Unauthorized"
}

403 Permission Denied​

{
"error": "Permission denied"
}

500 Internal Server Error​

{
"error": "Internal Server Error"
}

Code Examples​

JavaScript/TypeScript​

interface ConfidentialEntity {
id: string;
name: string;
description: string;
industryType: string;
isConfidential: true;
status: 'active' | 'pending' | 'suspended' | 'archived';
addedBy: string;
createdAt: string;
updatedAt: string;
logoUrl?: string;
websiteUrl?: string;
socialLinks?: {
linkedin?: string;
twitter?: string;
facebook?: string;
instagram?: string;
};
certifications?: string[];
partnerships?: string[];
memberCount?: number;
opportunityCount?: number;
}

interface ConfidentialEntitiesResponse {
entities: ConfidentialEntity[];
lastVisible: string | null;
totalPages: number;
totalEntities: number;
}

async function getConfidentialEntities(
page: number = 1,
limit: number = 20,
sort: string = 'createdAt:desc',
filter?: string
): Promise<ConfidentialEntitiesResponse> {
const params = new URLSearchParams({
page: page.toString(),
limit: limit.toString(),
sort,
...(filter && { filter })
});

const response = await fetch(`/api/confidential/entities?${params}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${getAuthToken()}`
}
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Failed to fetch confidential entities');
}

return response.json();
}

// Usage
try {
const result = await getConfidentialEntities(1, 10, 'name:asc', 'active');
console.log(`Found ${result.totalEntities} confidential entities`);
result.entities.forEach(entity => {
console.log(`- ${entity.name} (${entity.industryType})`);
});
} catch (error) {
console.error('Error fetching confidential entities:', error.message);
}

React Hook Example​

import { useState, useEffect } from 'react';

interface UseConfidentialEntitiesResult {
entities: ConfidentialEntity[];
loading: boolean;
error: string | null;
totalPages: number;
totalEntities: number;
loadMore: () => void;
hasMore: boolean;
refresh: () => void;
}

function useConfidentialEntities(
initialLimit: number = 20,
initialSort: string = 'createdAt:desc'
): UseConfidentialEntitiesResult {
const [entities, setEntities] = useState<ConfidentialEntity[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(0);
const [totalEntities, setTotalEntities] = useState(0);
const [lastVisible, setLastVisible] = useState<string | null>(null);

const fetchEntities = async (resetPage: boolean = false) => {
try {
setLoading(true);
setError(null);

const currentPage = resetPage ? 1 : page;
const result = await getConfidentialEntities(
currentPage,
initialLimit,
initialSort
);

if (resetPage) {
setEntities(result.entities);
setPage(1);
} else {
setEntities(prev => [...prev, ...result.entities]);
}

setTotalPages(result.totalPages);
setTotalEntities(result.totalEntities);
setLastVisible(result.lastVisible);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
};

useEffect(() => {
fetchEntities(true);
}, [initialLimit, initialSort]);

const loadMore = () => {
if (page < totalPages) {
setPage(prev => prev + 1);
fetchEntities();
}
};

const refresh = () => {
fetchEntities(true);
};

return {
entities,
loading,
error,
totalPages,
totalEntities,
loadMore,
hasMore: page < totalPages,
refresh
};
}

// Usage in component
function ConfidentialEntitiesList() {
const {
entities,
loading,
error,
totalEntities,
loadMore,
hasMore,
refresh
} = useConfidentialEntities(10, 'name:asc');

if (loading && entities.length === 0) {
return <div>Loading confidential entities...</div>;
}

if (error) {
return (
<div className="text-red-600">
Error: {error}
<button onClick={refresh} className="ml-2 px-3 py-1 bg-blue-500 text-white rounded">
Retry
</button>
</div>
);
}

return (
<div>
<div className="mb-4">
<h2>Confidential Entities ({totalEntities})</h2>
<button onClick={refresh} className="px-3 py-1 bg-gray-500 text-white rounded">
Refresh
</button>
</div>

<div className="grid gap-4">
{entities.map(entity => (
<div key={entity.id} className="border p-4 rounded-lg bg-gray-50">
<div className="flex items-center gap-3 mb-2">
{entity.logoUrl && (
<img src={entity.logoUrl} alt={entity.name} className="w-12 h-12 rounded" />
)}
<div>
<h3 className="font-semibold">{entity.name}</h3>
<span className="text-sm text-gray-600">{entity.industryType}</span>
</div>
<span className="ml-auto px-2 py-1 bg-red-100 text-red-800 text-xs rounded">
CONFIDENTIAL
</span>
</div>

<p className="text-gray-700 mb-3">{entity.description}</p>

<div className="flex gap-4 text-sm text-gray-600">
<span>πŸ‘₯ {entity.memberCount} members</span>
<span>🎯 {entity.opportunityCount} opportunities</span>
<span>πŸ“… Founded {entity.foundedYear}</span>
</div>
</div>
))}
</div>

{hasMore && (
<button
onClick={loadMore}
disabled={loading}
className="mt-4 px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
>
{loading ? 'Loading...' : 'Load More'}
</button>
)}
</div>
);
}

cURL Example​

# Get confidential entities with pagination
curl -X GET "https://ring.ck.ua/api/confidential/entities?page=1&limit=10&sort=name:asc" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"

# Get active confidential entities only
curl -X GET "https://ring.ck.ua/api/confidential/entities?filter=active&limit=20" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"

# Expected response
# {
# "entities": [...],
# "lastVisible": "entity_confidential_123",
# "totalPages": 5,
# "totalEntities": 87
# }

Python Example​

import requests
from typing import List, Optional, Dict, Any

class ConfidentialEntitiesClient:
def __init__(self, base_url: str, token: str):
self.base_url = base_url
self.headers = {"Authorization": f"Bearer {token}"}

def get_confidential_entities(
self,
page: int = 1,
limit: int = 20,
sort: str = "createdAt:desc",
filter_status: Optional[str] = None
) -> Dict[str, Any]:
"""Fetch confidential entities with pagination"""
params = {
"page": page,
"limit": limit,
"sort": sort
}

if filter_status:
params["filter"] = filter_status

response = requests.get(
f"{self.base_url}/api/confidential/entities",
headers=self.headers,
params=params
)

if response.status_code == 401:
raise PermissionError("Unauthorized - check your authentication token")
elif response.status_code == 403:
raise PermissionError("Permission denied - CONFIDENTIAL or ADMIN role required")
elif response.status_code != 200:
response.raise_for_status()

return response.json()

def get_all_confidential_entities(
self,
limit: int = 20,
sort: str = "createdAt:desc",
filter_status: Optional[str] = None
) -> List[Dict[str, Any]]:
"""Fetch all confidential entities across all pages"""
all_entities = []
page = 1

while True:
result = self.get_confidential_entities(page, limit, sort, filter_status)
all_entities.extend(result["entities"])

if page >= result["totalPages"]:
break

page += 1

return all_entities

# Usage
client = ConfidentialEntitiesClient("https://ring.ck.ua", "your_jwt_token")

try:
# Get first page of confidential entities
result = client.get_confidential_entities(page=1, limit=10, sort="name:asc")
print(f"Found {result['totalEntities']} confidential entities")

for entity in result["entities"]:
print(f"- {entity['name']} ({entity['industryType']})")

# Get all active confidential entities
active_entities = client.get_all_confidential_entities(
limit=50,
sort="name:asc",
filter_status="active"
)
print(f"\nFound {len(active_entities)} active confidential entities")

except PermissionError as e:
print(f"Access denied: {e}")
except Exception as e:
print(f"Error: {e}")

Authorization Requirements​

Required Roles​

  • CONFIDENTIAL: Premium users with confidential access
  • ADMIN: Full platform administrators

Role Verification Process​

// Authorization check logic
function hasConfidentialAccess(userRole: UserRole): boolean {
return userRole === UserRole.CONFIDENTIAL || userRole === UserRole.ADMIN;
}

Session Requirements​

  • Valid JWT token in Authorization header
  • Active session with appropriate role
  • Session must not be expired

Security Considerations​

Access Control​

  1. Strict Role Checking: Only CONFIDENTIAL and ADMIN users allowed
  2. Session Validation: Active authentication session required
  3. No Public Access: No anonymous or guest access permitted
  4. Audit Logging: All access attempts logged for security monitoring

Response Security​

  1. No Caching: Cache-Control headers prevent response caching
  2. Sensitive Data: Contains confidential organizational information
  3. Rate Limiting: Standard API rate limits apply
  4. HTTPS Only: Secure transport required in production

Data Protection​

  • Confidential entities marked with isConfidential: true
  • Enhanced privacy controls for sensitive information
  • Restricted visibility even within the platform
  • Regular security audits and access reviews

Error Handling​

Common Error Scenarios​

  1. Unauthorized Access (401)

    • Missing JWT token
    • Invalid or expired token
    • Solution: Provide valid authentication
  2. Permission Denied (403)

    • User lacks CONFIDENTIAL or ADMIN role
    • Session role insufficient
    • Solution: Contact admin for role upgrade
  3. Server Error (500)

    • Database connection issues
    • Internal service errors
    • Solution: Retry request or contact support

Performance Considerations​

Pagination​

  • Default limit: 20 entities per page
  • Maximum limit: 100 entities per page
  • Cursor-based pagination with startAfter parameter
  • Total count provided for UI pagination

Caching​

  • No client-side caching due to sensitivity
  • No CDN caching for security
  • Fresh data on every request
  • Server-side optimization for performance

Indexing​

  • Optimized database queries for common filters
  • Compound indexes for sort combinations
  • Efficient pagination with Firestore cursors

Testing Examples​

Unit Test Example​

describe('GET /api/confidential/entities', () => {
it('should return confidential entities for CONFIDENTIAL user', async () => {
const response = await request(app)
.get('/api/confidential/entities?page=1&limit=10')
.set('Authorization', `Bearer ${confidentialUserToken}`)
.expect(200);

expect(response.body).toHaveProperty('entities');
expect(response.body).toHaveProperty('totalPages');
expect(response.body).toHaveProperty('totalEntities');
expect(response.body.entities).toBeInstanceOf(Array);

// Verify all entities are marked as confidential
response.body.entities.forEach(entity => {
expect(entity.isConfidential).toBe(true);
});
});

it('should return 403 for regular user', async () => {
const response = await request(app)
.get('/api/confidential/entities')
.set('Authorization', `Bearer ${regularUserToken}`)
.expect(403);

expect(response.body.error).toBe('Permission denied');
});

it('should return 401 for unauthenticated request', async () => {
const response = await request(app)
.get('/api/confidential/entities')
.expect(401);

expect(response.body.error).toBe('Unauthorized');
});

it('should support pagination parameters', async () => {
const response = await request(app)
.get('/api/confidential/entities?page=2&limit=5&sort=name:asc')
.set('Authorization', `Bearer ${adminToken}`)
.expect(200);

expect(response.body.entities.length).toBeLessThanOrEqual(5);
});

it('should support filtering by status', async () => {
const response = await request(app)
.get('/api/confidential/entities?filter=active')
.set('Authorization', `Bearer ${confidentialUserToken}`)
.expect(200);

response.body.entities.forEach(entity => {
expect(entity.status).toBe('active');
});
});
});

Best Practices​

For Developers​

  1. Role Verification: Always verify user has appropriate role before making requests
  2. Error Handling: Implement proper error handling for 401/403 responses
  3. No Caching: Respect no-cache headers for security
  4. Pagination: Use proper pagination for large datasets
  5. Loading States: Show appropriate loading indicators

For Administrators​

  1. Access Reviews: Regularly review who has CONFIDENTIAL access
  2. Audit Monitoring: Monitor access logs for suspicious activity
  3. Role Management: Carefully manage CONFIDENTIAL role assignments
  4. Security Training: Ensure team understands confidential data handling

For Security​

  1. HTTPS Only: Never access over HTTP in production
  2. Token Management: Secure JWT token storage and transmission
  3. Session Monitoring: Monitor for unusual access patterns
  4. Data Classification: Ensure confidential entities are properly marked

Changelog​

  • v1.0.0 - Initial implementation with basic confidential access
  • v1.1.0 - Added pagination and filtering support
  • v1.2.0 - Enhanced security with no-cache headers
  • v1.3.0 - Improved error handling and logging
  • v1.4.0 - Added audit logging and access monitoring