This guide shows you how to take a live Sahha webhook event, pass the relevant Sahha data into Claude, and return a structured output that your app can display or act on.
What you are building
The integration flow is:
Sahha SDK in your app
↓
Sahha generates data
↓
Sahha webhook sends event to your backend
↓
Your backend extracts and formats the payload
↓
Claude Sonnet generates an output
↓
Your app stores or displays the resultA common use case is turning fresh Sahha data into:
- a daily summary
- a personalised engagement message
- a short lifestyle insight
- a structured JSON payload for your UI
Prerequisites
Before you start, make sure you already have:
- Sahha SDK integrated into your app
- a live Sahha webhook configured and receiving events
- a backend endpoint that can receive webhook payloads
- an Anthropic API key
Recommended architecture
Keep your Claude integration on your server, not in your client app.
Your backend should:
- receive the Sahha webhook
- validate and parse the incoming payload
- extract the Sahha fields you want to use
- build a prompt for Claude
- request a structured output
- store or return the result
Why use Claude here?
Claude is useful when you want to transform Sahha data into consistent, product-ready outputs.
For this workflow, structured outputs are especially useful because they let you return machine-readable JSON that can be rendered directly in your UI or used in downstream automation.
Example output shape
In this example, Claude will return:
{
"headline": "Poor recovery trend detected",
"summary": "The user appears to have had reduced recovery over the last 3 days.",
"recommendation": "Reduce cognitive load tonight and prioritise an earlier sleep window.",
"tone": "supportive"
}1. Install the Anthropic SDK
npm install @anthropic-ai/sdk2. Create a webhook endpoint
Below is a minimal Node.js example using Express. You can adapt the same pattern for Next.js, Fastify, Cloudflare Workers, or your preferred backend framework.
import express from 'express'
const app = express()
app.use(express.json())
app.post('/webhooks/sahha', async (req, res) => {
try {
const payload = req.body
// Optional: validate webhook authenticity here.
// Optional: ignore event types you do not want to process.
const result = await generateClaudeOutput(payload)
// Save the result to your database, send it to your app,
// or trigger the next step in your workflow.
console.log(result)
return res.status(200).json({ ok: true, result })
} catch (error) {
console.error(error)
return res.status(500).json({
ok: false,
error: 'Failed to process webhook',
})
}
})
app.listen(3000, () => {
console.log('Listening on port 3000')
})3. Extract the Sahha data you want to send
Your webhook payload may contain more data than you need. In most cases, you should reduce it to only the fields that matter for the output you want to generate.
For example:
function mapSahhaPayload(payload: any) {
return {
profileId: payload.profileId,
timestamp: payload.timestamp,
scores: payload.scores,
biomarkers: payload.biomarkers,
// Add or remove fields based on your webhook payload shape.
}
}The goal is to give Claude enough context to generate a strong answer without sending unnecessary raw data.
4. Send the Sahha context to Claude
This example uses the Anthropic Messages API through the official SDK with a Sonnet model and JSON schema output.
import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
})
async function generateClaudeOutput(payload: any) {
const sahha = mapSahhaPayload(payload)
const response = await client.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 400,
system:
'You are a behavioural health assistant. Return concise, safe, supportive outputs for use inside a product experience.',
messages: [
{
role: 'user',
content: [
'You will receive Sahha webhook data from a health and lifestyle application.',
'Using only the data below, create a short output for the end user.',
'Do not diagnose.',
'Do not make medical claims.',
'Keep the response practical, brief, and supportive.',
'',
'Sahha data:',
JSON.stringify(sahha, null, 2),
].join('\n'),
},
],
output_config: {
format: {
type: 'json_schema',
schema: {
type: 'object',
additionalProperties: false,
properties: {
headline: { type: 'string' },
summary: { type: 'string' },
recommendation: { type: 'string' },
tone: {
type: 'string',
enum: ['supportive', 'neutral', 'encouraging'],
},
},
required: ['headline', 'summary', 'recommendation', 'tone'],
},
},
},
})
const textBlock = response.content.find((block) => block.type === 'text')
if (!textBlock) {
throw new Error('Claude did not return a text response')
}
return JSON.parse(textBlock.text)
}5. Return or store the output
Once Claude responds, you can:
- store the output in your database
- attach it to a user timeline or feed
- send it to your frontend in real time
- use it to trigger another workflow
Example response:
{
"headline": "Poor recovery trend detected",
"summary": "Your recent data suggests recovery has trended lower over the last few days.",
"recommendation": "Aim for a lighter evening and an earlier sleep window tonight.",
"tone": "supportive"
}Prompting tips
A few implementation details matter here.
Keep the Sahha context focused
Only send the fields that are relevant to the output you want. Cleaner inputs usually lead to more predictable outputs.
Keep the schema tight
If the response is going into a product UI, define a strict JSON schema and keep the number of fields small.
Be explicit about boundaries
If this output is user-facing, instruct the model clearly:
Avoid medical claims.
Do not diagnose.
Keep the tone supportive.
Write for an end user, not a clinician.Plan for refusals and token limits
If Claude refuses the request or hits max_tokens, the output may not match your schema. Your backend should handle those cases gracefully.
Testing the flow
A simple way to test this integration is:
- trigger a real or test Sahha event
- confirm your webhook receives the payload
- log the mapped Sahha data
- send it to Claude
- inspect the returned JSON before saving it
You should also test:
- missing fields
- malformed payloads
- duplicate webhook deliveries
- Anthropic timeout or non-200 responses
- incomplete outputs caused by token limits
Production notes
Before shipping this flow, make sure you:
- verify webhook authenticity
- implement retries and idempotency
- avoid passing unnecessary personal data
- log failures without exposing sensitive data
- monitor cost and latency
- validate the parsed output before saving it
Example use cases
You can reuse this pattern for:
- daily readiness summaries
- recovery-based engagement copy
- behavioural nudges
- personalised onboarding follow-ups
- coach-facing or admin-facing summaries
Next step
Once this is working, the next improvement is usually to standardise multiple output types.
For example, you might create separate prompt templates and schemas for:
- user-facing summaries
- coach-facing insights
- high-risk flags
- weekly recaps
That lets the same Sahha webhook power multiple downstream experiences.