This guide shows you how to take a live Sahha webhook event, pass the relevant Sahha data into Gemini, 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
↓
Gemini 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
- a Gemini API key
Recommended architecture
Keep your Gemini 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 Gemini
- request a structured output
- store or return the result
Why use Gemini here?
Gemini is useful when you want to transform Sahha data into consistent, product-ready outputs.
For this workflow, structured JSON 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, Gemini 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 Gemini SDK
npm install @google/genai2. 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 generateGeminiOutput(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 Gemini enough context to generate a strong answer without sending unnecessary raw data.
4. Send the Sahha context to Gemini
This example uses the Google GenAI SDK with a Gemini 3 model and a JSON schema response.
import { GoogleGenAI } from '@google/genai'
const ai = new GoogleGenAI({
apiKey: process.env.GEMINI_API_KEY,
})
async function generateGeminiOutput(payload: any) {
const sahha = mapSahhaPayload(payload)
const prompt = [
'You are a behavioural health assistant.',
'Return concise, safe, supportive outputs for use inside a product experience.',
'',
'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')
const response = await ai.models.generateContent({
model: 'gemini-3-flash-preview',
contents: prompt,
config: {
responseMimeType: 'application/json',
responseJsonSchema: {
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'],
},
},
})
return JSON.parse(response.text)
}5. Return or store the output
Once Gemini 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.Pick the right Gemini model for the job
For lightweight webhook transforms, a fast Gemini model is usually enough. If you later need more complex synthesis, you can swap to a more capable Gemini 3 series model.
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 Gemini
- inspect the returned JSON before saving it
You should also test:
- missing fields
- malformed payloads
- duplicate webhook deliveries
- Gemini timeout or non-200 responses
- incomplete or invalid outputs caused by prompt issues
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
- pin and test the exact model version you want to use
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.