March 11, 2026 · 6 min read

Build a Health Agent with ChatGPT and Sahha

Use Sahha webhooks and OpenAI's ChatGPT to build an AI health agent that turns real-time wearable data into structured insights for your app users.

This guide shows you how to take a live Sahha webhook event, pass the relevant Sahha data into OpenAI, 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

OpenAI GPT-5 generates an output

Your app stores or displays the result

A 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 OpenAI API key
Prerequisite: This guide assumes your app is already sending data through the Sahha SDK and that your Sahha webhook is live.

Keep your OpenAI integration on your server, not in your client app.

Your backend should:

  1. receive the Sahha webhook
  2. validate and parse the incoming payload
  3. extract the Sahha fields you want to use
  4. build a prompt for OpenAI
  5. request a structured output
  6. store or return the result

Why use OpenAI here?

OpenAI 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, OpenAI 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 OpenAI SDK

npm install openai

2. 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 generateOpenAIOutput(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 OpenAI enough context to generate a strong answer without sending unnecessary raw data.

4. Send the Sahha context to OpenAI

This example uses the OpenAI Responses API with a GPT-5 family model and Structured Outputs.

import OpenAI from 'openai'

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
})

async function generateOpenAIOutput(payload: any) {
  const sahha = mapSahhaPayload(payload)

  const response = await client.responses.create({
    model: 'gpt-5.4',
    reasoning: {
      effort: 'low',
    },
    input: [
      {
        role: 'system',
        content:
          'You are a behavioural health assistant. Return concise, safe, supportive outputs for use inside a product experience.',
      },
      {
        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'),
      },
    ],
    text: {
      format: {
        type: 'json_schema',
        name: 'sahha_user_summary',
        strict: true,
        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'],
        },
      },
    },
    max_output_tokens: 400,
  })

  return JSON.parse(response.output_text)
}

5. Return or store the output

Once OpenAI 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.

Use reasoning effort intentionally

For simple summaries or transforms, low is usually enough. If you are doing more complex synthesis, you can experiment with higher reasoning settings.

Testing the flow

A simple way to test this integration is:

  1. trigger a real or test Sahha event
  2. confirm your webhook receives the payload
  3. log the mapped Sahha data
  4. send it to OpenAI
  5. inspect the returned JSON before saving it

You should also test:

  • missing fields
  • malformed payloads
  • duplicate webhook deliveries
  • OpenAI 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
  • set sensible token limits
  • monitor cost and latency
Production recommendation: Do not pass unnecessary health or behavioural data to third-party services. Only send the minimum context required to generate the output you need.

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.