Skip to main content
CID222Documentation

Integration Examples

Learn how to integrate CID222 into your applications with these real-world code examples across different languages and frameworks.

Responses stream as SSE

/chat/completions and session messages always return Server-Sent Events — read the stream and accumulate the content field of events that carry one; the complete filtered answer arrives as a single filtered-response event. There is no choices[] JSON body.

JavaScript / Node.js

Basic Request

Node.js - Collect the stream
1async function chat(userMessage) {
2 const res = await fetch('https://api.cid222.ai/chat/completions', {
3 method: 'POST',
4 headers: {
5 'Authorization': `Bearer ${process.env.CID222_API_KEY}`,
6 'Content-Type': 'application/json',
7 },
8 body: JSON.stringify({
9 model: 'gpt-4o',
10 messages: [
11 { role: 'system', content: 'You are a helpful assistant.' },
12 { role: 'user', content: userMessage }
13 ]
14 })
15 });
16
17 // /chat/completions always streams Server-Sent Events
18 const reader = res.body.getReader();
19 const decoder = new TextDecoder();
20 let answer = '';
21
22 while (true) {
23 const { done, value } = await reader.read();
24 if (done) break;
25 for (const line of decoder.decode(value).split('\n')) {
26 if (!line.startsWith('data: ')) continue;
27 const data = line.slice(6);
28 if (data === '[DONE]') return answer;
29 const event = JSON.parse(data);
30 // Input blocked (type: "content_rejected")
31 if (event.error) throw new Error('Blocked: ' + event.error);
32 // Model text: top-level "content" string. The full filtered answer
33 // arrives as one event (id: "filtered-response", finish_reason: "stop").
34 if (!event.type && typeof event.content === 'string') {
35 answer = event.finish_reason === 'stop' ? event.content : answer + event.content;
36 }
37 }
38 }
39 return answer;
40}

Streaming Response

Node.js - Stream tokens & filter events
1async function streamChat(message, onToken) {
2 const res = await fetch('https://api.cid222.ai/chat/completions', {
3 method: 'POST',
4 headers: {
5 'Authorization': `Bearer ${process.env.CID222_API_KEY}`,
6 'Content-Type': 'application/json',
7 },
8 body: JSON.stringify({
9 model: 'gpt-4o',
10 messages: [{ role: 'user', content: message }]
11 })
12 });
13
14 const reader = res.body.getReader();
15 const decoder = new TextDecoder();
16
17 while (true) {
18 const { done, value } = await reader.read();
19 if (done) break;
20 for (const line of decoder.decode(value).split('\n')) {
21 if (!line.startsWith('data: ')) continue;
22 const data = line.slice(6);
23 if (data === '[DONE]') return;
24
25 const event = JSON.parse(data);
26 // Input blocked before reaching the provider (type: "content_rejected")
27 if (event.error) throw new Error('Blocked: ' + event.error);
28
29 switch (event.type) {
30 case 'user_message_processed':
31 // PII in the prompt was masked/flagged before sending
32 console.warn('Prompt filtered:', event.masked_count, 'masked,',
33 event.flagged_count, 'flagged');
34 break;
35 case 'output_content_rejected':
36 throw new Error('Blocked: ' + event.reason);
37 case 'output_content_warning':
38 console.warn('Warning:', event.message);
39 break;
40 case undefined:
41 // Model text — the complete filtered answer arrives as one event
42 // (id: "filtered-response", finish_reason: "stop")
43 if (typeof event.content === 'string') onToken(event.content);
44 break;
45 }
46 }
47 }
48}

Python

Python - Stream with requests
1import os
2import json
3import requests
4
5def stream_chat(message: str) -> str:
6 response = requests.post(
7 'https://api.cid222.ai/chat/completions',
8 headers={
9 'Authorization': f'Bearer {os.environ["CID222_API_KEY"]}',
10 'Content-Type': 'application/json',
11 },
12 json={
13 'model': 'gpt-4o',
14 'messages': [{'role': 'user', 'content': message}],
15 },
16 stream=True,
17 )
18
19 answer = ''
20 for line in response.iter_lines():
21 if not line:
22 continue
23 line = line.decode('utf-8')
24 if not line.startswith('data: '):
25 continue
26 data = line[6:]
27 if data == '[DONE]':
28 break
29 event = json.loads(data)
30 if 'error' in event: # input blocked (type "content_rejected")
31 raise RuntimeError('Blocked: ' + event['error'])
32 if event.get('type') == 'output_content_rejected':
33 raise RuntimeError('Blocked: ' + str(event.get('reason', '')))
34 if not event.get('type') and isinstance(event.get('content'), str):
35 # Model text. The complete filtered answer arrives as one event
36 # (id "filtered-response", finish_reason "stop").
37 if event.get('finish_reason') == 'stop':
38 answer = event['content']
39 else:
40 answer += event['content']
41 print(event['content'], end='', flush=True)
42 print()
43 return answer
44
45# Usage
46stream_chat("Explain quantum computing in simple terms.")

Standalone Detection

Python - Scan text without an LLM
1import os
2import requests
3
4def detect(text: str) -> dict:
5 response = requests.post(
6 'https://api.cid222.ai/api/v1/guardrails/detect',
7 headers={
8 'Authorization': f'Bearer {os.environ["CID222_API_KEY"]}',
9 'Content-Type': 'application/json',
10 },
11 json={'text': text, 'check_type': 'prompt'},
12 )
13 return response.json()
14
15result = detect("Email me at john@example.com")
16print(result['action']) # e.g. "mask"
17print(result['maskedText']) # "Email me at [EMAIL]"

React / Next.js

React - Chat Hook
1import { useState, useCallback } from 'react';
2
3export function useChat() {
4 const [messages, setMessages] = useState([]);
5 const [isLoading, setIsLoading] = useState(false);
6
7 const sendMessage = useCallback(async (content: string) => {
8 setIsLoading(true);
9 const userMessage = { role: 'user', content };
10 setMessages(prev => [...prev, userMessage]);
11
12 try {
13 // Your server route proxies CID222 and forwards the SSE stream
14 const res = await fetch('/api/chat', {
15 method: 'POST',
16 headers: { 'Content-Type': 'application/json' },
17 body: JSON.stringify({ messages: [...messages, userMessage] })
18 });
19
20 const reader = res.body.getReader();
21 const decoder = new TextDecoder();
22 let answer = '';
23 setMessages(prev => [...prev, { role: 'assistant', content: '' }]);
24
25 while (true) {
26 const { done, value } = await reader.read();
27 if (done) break;
28 for (const line of decoder.decode(value).split('\n')) {
29 if (!line.startsWith('data: ')) continue;
30 const data = line.slice(6);
31 if (data === '[DONE]') break;
32 const event = JSON.parse(data);
33 if (event.error) throw new Error('Blocked: ' + event.error);
34 if (!event.type && typeof event.content === 'string') {
35 // Full filtered answer arrives as one event (finish_reason: "stop")
36 answer = event.finish_reason === 'stop' ? event.content : answer + event.content;
37 setMessages(prev => {
38 const next = [...prev];
39 next[next.length - 1] = { role: 'assistant', content: answer };
40 return next;
41 });
42 }
43 }
44 }
45 } catch (error) {
46 console.error('Chat error:', error);
47 } finally {
48 setIsLoading(false);
49 }
50 }, [messages]);
51
52 return { messages, sendMessage, isLoading };
53}
For production React apps, consider using the CID222 SDK which handles streaming, error recovery, and type safety automatically.

cURL Examples

cURL - Basic Request
curl -N -X POST https://api.cid222.ai/chat/completions \
-H "Authorization: Bearer $CID222_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"messages": [
{"role": "user", "content": "Hello, world!"}
]
}'
cURL - Create Session (JWT)
# Create a session (sessions use a user JWT)
curl -X POST https://api.cid222.ai/sessions \
-H "Authorization: Bearer $CID222_JWT" \
-H "Content-Type: application/json" \
-d '{
"session_name": "Demo",
"user_id": "user-123"
}'
# Send a message — choose the model per message
curl -N -X POST https://api.cid222.ai/sessions/SESSION_ID/messages \
-H "Authorization: Bearer $CID222_JWT" \
-H "Content-Type: application/json" \
-d '{"content": "What can you help me with?", "model": "gpt-4o"}'