Skip to Content

Integration Examples

Real-world patterns for integrating with Cendriix via the A2A Public API.

HR Portal — Resume Screening

Automate resume screening by invoking an agent that analyzes resumes against job descriptions.

import { A2AClient } from '@cendriix/a2a'; const client = new A2AClient({ apiKey: process.env.CENDRIIX_API_KEY! }); app.post('/webhooks/greenhouse', async (req, res) => { const { candidate, job, resume_url } = req.body; const task = await client.invoke('resume-screener', { message: `Screen this resume against the job description. Produce a structured scorecard with: fit score (0-100), strengths, concerns, and a hire/pass recommendation.`, context: { candidateName: candidate.name, jobTitle: job.title, jobDescription: job.description, requiredSkills: job.required_skills, resumeUrl: resume_url, }, }); if (task.status === 'COMPLETED') { const scorecard = JSON.parse( task.artifacts.find(a => a.name === 'scorecard')?.parts[0]?.text ?? '{}', ); await updateGreenhouseScorecard(candidate.id, scorecard); if (scorecard.fitScore >= 70) { await notifySlack(`Strong candidate for ${job.title}: ${candidate.name} (${scorecard.fitScore}/100)`); } } res.status(200).send('OK'); });

Chef Portal — Weekly Menu Planning

Stream menu artifacts in real-time as the agent generates a weekly plan:

async function generateWeeklyMenu(params: { cuisineType: string; dietaryRestrictions: string[]; seasonalIngredients: string[]; budget: number; covers: number; }) { const stream = client.stream('menu-planner', { message: `Generate a 7-day dinner menu for a ${params.cuisineType} restaurant. Budget: $${params.budget}/week for ${params.covers} covers/night.`, context: params, }); for await (const event of stream) { if (event.type === 'artifact') { const art = event.event.artifact; switch (art.name) { case 'weekly-menu': updateMenuDisplay(JSON.parse(art.parts[0]?.text ?? '{}')); break; case 'shopping-list': updateShoppingList(JSON.parse(art.parts[0]?.text ?? '[]')); break; case 'cost-breakdown': updateCostChart(JSON.parse(art.parts[0]?.text ?? '{}')); break; } } } }

Marketing Ops — Campaign Generation

Generate multi-channel campaign content from a brief:

interface CampaignBrief { productName: string; targetAudience: string; campaignGoal: string; channels: ('email' | 'social' | 'landing_page')[]; tone: string; keyMessages: string[]; } async function generateCampaign(brief: CampaignBrief) { const task = await client.invoke('campaign-generator', { message: `Generate a multi-channel marketing campaign for ${brief.productName}. Target: ${brief.targetAudience}. Goal: ${brief.campaignGoal}. Channels: ${brief.channels.join(', ')}. Tone: ${brief.tone}.`, context: brief, }, { timeout: 120_000 }); for (const artifact of task.artifacts) { switch (artifact.name) { case 'email-sequence': await scheduleSendgridSequence(JSON.parse(artifact.parts[0]?.text ?? '[]')); break; case 'social-posts': await scheduleBufferPosts(JSON.parse(artifact.parts[0]?.text ?? '[]')); break; case 'landing-page-copy': await createWebflowPage(JSON.parse(artifact.parts[0]?.text ?? '{}')); break; } } }

CI/CD Pipeline — Docker Build + Deploy

Use OIDC workload identity federation for zero-secret authentication in GitHub Actions:

name: Deploy with Cendriix on: push: branches: [main] permissions: id-token: write jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Get OIDC token id: oidc run: | TOKEN=$(curl -sS \ -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=cendriix.ai") echo "token=$TOKEN" >> $GITHUB_OUTPUT - name: Exchange for Cendriix access token id: exchange run: | ACCESS_TOKEN=$(curl -sS -X POST https://api.cendriix.ai/v1/oauth/token \ -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \ -d subject_token_type=urn:ietf:params:oauth:token-type:jwt \ -d subject_token="${{ steps.oidc.outputs.token }}" \ -d scope="agents:invoke tasks:read" | jq -r .access_token) echo "access_token=$ACCESS_TOKEN" >> $GITHUB_OUTPUT - name: Deploy via Cendriix run: | npx @cendriix/a2a-cli invoke deployer \ --token "${{ steps.exchange.outputs.access_token }}" \ --message "Build and deploy ${{ github.repository }}@${{ github.sha }}" \ --wait --timeout 600

Slack Bot — Agent Invocation

Invoke agents from Slack via slash commands:

import { App } from '@slack/bolt'; import { A2AClient } from '@cendriix/a2a'; const slackApp = new App({ token: process.env.SLACK_BOT_TOKEN!, signingSecret: process.env.SLACK_SIGNING_SECRET!, }); const cendriix = new A2AClient({ apiKey: process.env.CENDRIIX_API_KEY! }); slackApp.command('/cendriix', async ({ command, ack, respond }) => { await ack(); const [agentSlug, ...messageParts] = command.text.split(' '); const message = messageParts.join(' '); if (!agentSlug || !message) { await respond({ text: 'Usage: `/cendriix <agent-name> <your request>`' }); return; } await respond({ text: `:hourglass_flowing_sand: Invoking \`${agentSlug}\`...`, response_type: 'in_channel' }); try { const task = await cendriix.invoke(agentSlug, { message }, { timeout: 120_000 }); if (task.status === 'COMPLETED') { const blocks = task.artifacts.map(artifact => ({ type: 'section' as const, text: { type: 'mrkdwn' as const, text: `*${artifact.name}*\n${artifact.parts[0]?.text ?? '(empty)'}` }, })); await respond({ text: `Agent \`${agentSlug}\` completed`, blocks, response_type: 'in_channel' }); } else { await respond({ text: `:x: Agent \`${agentSlug}\` failed: ${task.error ?? task.status}`, response_type: 'in_channel' }); } } catch (err) { await respond({ text: `:warning: Error: ${(err as Error).message}`, response_type: 'ephemeral' }); } });

Common patterns

Idempotent retries

const task = await client.invoke('deployer', { message: `Deploy ${sha}` }, { idempotencyKey: `deploy-${sha}-${env}`, });

Session-based conversations

const sessionId = `onboarding-${customerId}`; await client.invoke('onboarding-agent', { message: 'Start onboarding for Acme Corp', sessionId }); await client.invoke('onboarding-agent', { message: 'Now configure their Jira integration', sessionId });
Last updated on