What you’ll build
An automated client onboarding workflow that creates a structured knowledge board from a client’s public web presence and industry data.- Board pre-populated with client website and industry reports
- AI-generated industry overview, stakeholder analysis, and key challenges
- Structured zones with action-item sticky notes
- Ready to share with the consulting or agency team
Prerequisites
- ChatGrid API key (get one here)
- Node.js 18+ or Python 3.10+
Step 1: Create a client board
curl -X POST https://api.chatgrid.ai/v1/boards \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Client: Meridian Health Systems - Onboarding"}'
const board = await fetch("https://api.chatgrid.ai/v1/boards", {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ name: "Client: Meridian Health Systems - Onboarding" }),
}).then((r) => r.json());
const boardId = board.data.id;
import requests
board = requests.post("https://api.chatgrid.ai/v1/boards",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"name": "Client: Meridian Health Systems - Onboarding"}).json()
board_id = board["data"]["id"]
Step 2: Add client website and industry report
Batch-add the client’s public pages and a relevant industry report as source nodes.curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/nodes/batch \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{"action": "create", "data": {"type": "url", "position": {"x": 0, "y": 0}, "data": {"url": "https://meridianhealth.com/about"}}},
{"action": "create", "data": {"type": "url", "position": {"x": 420, "y": 0}, "data": {"url": "https://meridianhealth.com/leadership"}}},
{"action": "create", "data": {"type": "url", "position": {"x": 840, "y": 0}, "data": {"url": "https://deloitte.com/insights/healthcare-outlook-2026"}}}
]
}'
const clientSources = [
{ type: "url", position: { x: 0, y: 0 }, data: { url: "https://meridianhealth.com/about" } },
{ type: "url", position: { x: 420, y: 0 }, data: { url: "https://meridianhealth.com/leadership" } },
{ type: "url", position: { x: 840, y: 0 }, data: { url: "https://deloitte.com/insights/healthcare-outlook-2026" } },
];
await fetch(`https://api.chatgrid.ai/v1/boards/${boardId}/nodes/batch`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
operations: clientSources.map((source) => ({ action: "create", data: source })),
}),
});
client_sources = [
{"type": "url", "position": {"x": 0, "y": 0}, "data": {"url": "https://meridianhealth.com/about"}},
{"type": "url", "position": {"x": 420, "y": 0}, "data": {"url": "https://meridianhealth.com/leadership"}},
{"type": "url", "position": {"x": 840, "y": 0}, "data": {"url": "https://deloitte.com/insights/healthcare-outlook-2026"}},
]
requests.post(f"https://api.chatgrid.ai/v1/boards/{board_id}/nodes/batch",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"operations": [{"action": "create", "data": source} for source in client_sources]})
Step 3: Vectorize all sources
curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/documents/vectorize \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Meridian Health Systems is expanding virtual care, modernizing patient intake, and consolidating analytics across regional clinics.",
"metadata": {"source": "meridianhealth.com/about", "type": "client-research"}
}'
const sourceTexts = [
{
content: "Meridian Health Systems is expanding virtual care, modernizing patient intake, and consolidating analytics across regional clinics.",
metadata: { source: "meridianhealth.com/about", type: "client-research" },
},
{
content: "Leadership page notes: CTO owns data platform modernization; COO owns intake efficiency and care coordination.",
metadata: { source: "meridianhealth.com/leadership", type: "stakeholders" },
},
];
await Promise.all(sourceTexts.map((source) =>
fetch(`https://api.chatgrid.ai/v1/boards/${boardId}/documents/vectorize`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify(source),
})
));
import concurrent.futures
source_texts = [
{"content": "Meridian Health Systems is expanding virtual care, modernizing patient intake, and consolidating analytics across regional clinics.", "metadata": {"source": "meridianhealth.com/about", "type": "client-research"}},
{"content": "Leadership page notes: CTO owns data platform modernization; COO owns intake efficiency and care coordination.", "metadata": {"source": "meridianhealth.com/leadership", "type": "stakeholders"}},
]
def vectorize(source):
return requests.post(f"https://api.chatgrid.ai/v1/boards/{board_id}/documents/vectorize",
headers={"Authorization": f"Bearer {API_KEY}"}, json=source)
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as pool:
list(pool.map(vectorize, source_texts))
Step 4: Generate AI analysis
Create a chat and ask AI for three deliverables: industry overview, stakeholder analysis, and key challenges.curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/chats \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Onboarding Analysis"}'
curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/chats/{chatId}/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Based on the client materials and industry report on this board, generate:\n1. Industry Overview: trends, market dynamics, regulatory landscape\n2. Stakeholder Analysis: key executives and their likely priorities\n3. Key Challenges: top 5 challenges this client faces\nBe specific to this client, not generic.",
"stream": false
}'
const chat = await fetch(`https://api.chatgrid.ai/v1/boards/${boardId}/chats`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ title: "Onboarding Analysis" }),
}).then((r) => r.json());
const report = await fetch(
`https://api.chatgrid.ai/v1/boards/${boardId}/chats/${chat.data.id}/messages`,
{
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
content: "Based on the client materials and industry report on this board, generate:\n1. Industry Overview: trends, market dynamics, regulatory landscape\n2. Stakeholder Analysis: key executives and their likely priorities\n3. Key Challenges: top 5 challenges this client faces\nBe specific to this client, not generic.",
stream: false,
}),
}
).then((r) => r.json());
chat = requests.post(f"https://api.chatgrid.ai/v1/boards/{board_id}/chats",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"title": "Onboarding Analysis"}).json()
report = requests.post(
f"https://api.chatgrid.ai/v1/boards/{board_id}/chats/{chat['data']['id']}/messages",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"content": "Based on the client materials and industry report on this board, generate:\n1. Industry Overview: trends, market dynamics, regulatory landscape\n2. Stakeholder Analysis: key executives and their likely priorities\n3. Key Challenges: top 5 challenges this client faces\nBe specific to this client, not generic.", "stream": False},
).json()
Step 5: Create structured zones with batch nodes
Organize the board into clear zones: one notepad per section, plus action-item sticky notes.curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/nodes/batch \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{"action": "create", "data": {"type": "document", "position": {"x": 0, "y": 420}, "data": {"content": "# Industry Overview\n\n[Paste section 1 from AI output]"}}},
{"action": "create", "data": {"type": "document", "position": {"x": 420, "y": 420}, "data": {"content": "# Stakeholder Analysis\n\n[Paste section 2 from AI output]"}}},
{"action": "create", "data": {"type": "document", "position": {"x": 840, "y": 420}, "data": {"content": "# Key Challenges\n\n[Paste section 3 from AI output]"}}},
{"action": "create", "data": {"type": "note", "position": {"x": 0, "y": 760}, "data": {"text": "ACTION: Schedule discovery call with CTO to validate tech priorities"}}},
{"action": "create", "data": {"type": "note", "position": {"x": 420, "y": 760}, "data": {"text": "ACTION: Request org chart from client contact"}}},
{"action": "create", "data": {"type": "note", "position": {"x": 840, "y": 760}, "data": {"text": "ACTION: Prepare pitch deck addressing top 3 challenges"}}}
]
}'
const sections = report.data.content.split(/(?=# )/).filter(Boolean);
const zoneNodes = [
{ type: "document", position: { x: 0, y: 420 }, data: { content: sections[0] || "# Industry Overview\n\n[Pending]" } },
{ type: "document", position: { x: 420, y: 420 }, data: { content: sections[1] || "# Stakeholder Analysis\n\n[Pending]" } },
{ type: "document", position: { x: 840, y: 420 }, data: { content: sections[2] || "# Key Challenges\n\n[Pending]" } },
{ type: "note", position: { x: 0, y: 760 }, data: { text: "ACTION: Schedule discovery call with CTO" } },
{ type: "note", position: { x: 420, y: 760 }, data: { text: "ACTION: Request org chart from client contact" } },
{ type: "note", position: { x: 840, y: 760 }, data: { text: "ACTION: Prepare pitch deck addressing top 3 challenges" } },
];
await fetch(`https://api.chatgrid.ai/v1/boards/${boardId}/nodes/batch`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
operations: zoneNodes.map((node) => ({ action: "create", data: node })),
}),
});
sections = [s for s in report["data"]["content"].split("# ") if s.strip()]
zone_nodes = [
{"type": "document", "position": {"x": 0, "y": 420}, "data": {"content": f"# {sections[0]}" if len(sections) > 0 else "# Industry Overview\n\n[Pending]"}},
{"type": "document", "position": {"x": 420, "y": 420}, "data": {"content": f"# {sections[1]}" if len(sections) > 1 else "# Stakeholder Analysis\n\n[Pending]"}},
{"type": "document", "position": {"x": 840, "y": 420}, "data": {"content": f"# {sections[2]}" if len(sections) > 2 else "# Key Challenges\n\n[Pending]"}},
{"type": "note", "position": {"x": 0, "y": 760}, "data": {"text": "ACTION: Schedule discovery call with CTO"}},
{"type": "note", "position": {"x": 420, "y": 760}, "data": {"text": "ACTION: Request org chart from client contact"}},
{"type": "note", "position": {"x": 840, "y": 760}, "data": {"text": "ACTION: Prepare pitch deck addressing top 3 challenges"}},
]
requests.post(f"https://api.chatgrid.ai/v1/boards/{board_id}/nodes/batch",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"operations": [{"action": "create", "data": node} for node in zone_nodes]})
What’s happening under the hood
The API stores source nodes on the board and vectorizes the text you provide. When the AI generates the analysis, it searches across vectorized content to find relevant passages from the client research and industry notes, producing a response grounded in source material rather than generic knowledge. The batch node endpoint applies all zone-node operations in one request.Next steps
Research Pipeline
Go deeper with multi-source research synthesis
Team Knowledge
Share the onboarding board with your whole team