Quickstart: Your First Bounded Health API Integration
Last updated: 2026-02-18
Time to complete: ~10 minutes
This guide takes you from zero to a working API integration. By the end you will have:
- Created an API key
- Made your first API call
- Set up a webhook subscription
- Verified a webhook signature
Prerequisites
- An employer admin account on Bounded Health (sign up at
/sign-up) - Your employer must be approved for API access
- Node.js 18+ installed (for code examples)
- A tool to make HTTP requests (
curl, Postman, or your code)
Step 1: Create an API key
Sign in to Bounded Health as an employer admin, then create an API key:
Via the UI: Navigate to your employer dashboard → API Keys → Create Key.
Via the API (using your browser session):
curl -X POST https://<YOUR_HOST>/api/employer/api-keys \
-H "content-type: application/json" \
-H "cookie: <YOUR_SESSION_COOKIE>" \
-d '{
"name": "My First Integration",
"scopes": ["cohort:read", "export:read", "fhir:read", "webhook:manage"]
}'
Expected response:
{
"id": "clu1abc...",
"name": "My First Integration",
"rawKey": "mt_live_a1b2c3d4e5f6...",
"scopes": ["cohort:read", "export:read", "fhir:read", "webhook:manage"],
"createdAt": "2026-02-18T12:00:00.000Z"
}
⚠️ Copy
rawKeynow! It is shown exactly once and cannot be retrieved later. Store it in a secret manager — never commit it to source control.
Set up your environment:
export MT_API_KEY="mt_live_a1b2c3d4e5f6..."
export MT_HOST="https://your-instance.Bounded Health.com"
Step 2: Make your first API call
Fetch the FHIR capability statement to verify your key works:
curl -s "$MT_HOST/api/fhir/metadata" \
-H "x-api-key: $MT_API_KEY" \
-H "x-api-version: 2026-02-01" \
-H "accept: application/fhir+json" | head -20
Expected response (truncated):
{
"resourceType": "CapabilityStatement",
"status": "active",
"fhirVersion": "4.0.1",
"format": ["application/fhir+json"],
"rest": [...]
}
If you get an error:
| Status | Meaning | Fix |
|---|---|---|
401 | Key is invalid or revoked | Double-check the mt_live_ key value |
403 | Missing scope or IP blocked | Add fhir:read scope; check IP allowlist |
400 | Unsupported API version | Use x-api-version: 2026-02-01 |
Step 3: Fetch real data
Search for FHIR Patient resources in your employer tenant:
curl -s "$MT_HOST/api/fhir/Patient?_count=5" \
-H "x-api-key: $MT_API_KEY" \
-H "x-api-version: 2026-02-01" \
-H "accept: application/fhir+json"
Expected response:
{
"resourceType": "Bundle",
"type": "searchset",
"total": 42,
"entry": [
{
"resource": {
"resourceType": "Patient",
"id": "user_abc123",
"identifier": [{ "value": "user_abc123" }],
"telecom": [{ "system": "email", "value": "patient@example.com" }]
}
}
]
}
Node.js equivalent:
const response = await fetch(`${process.env.MT_HOST}/api/fhir/Patient?_count=5`, {
headers: {
"x-api-key": process.env.MT_API_KEY!,
"x-api-version": "2026-02-01",
"accept": "application/fhir+json",
},
});
const bundle = await response.json();
console.log(`Found ${bundle.total} patients`);
for (const entry of bundle.entry ?? []) {
console.log(` Patient: ${entry.resource.id}`);
}
Step 4: Set up a webhook
Create a webhook subscription to receive real-time events:
curl -X POST "$MT_HOST/api/employer/webhooks" \
-H "x-api-key: $MT_API_KEY" \
-H "x-api-version: 2026-02-01" \
-H "content-type: application/json" \
-d '{
"url": "https://your-server.example.com/webhooks/Bounded Health",
"events": ["cohort.uploaded", "export.ready", "simulation.completed"],
"description": "My first webhook"
}'
Expected response:
{
"id": "whk_abc123...",
"url": "https://your-server.example.com/webhooks/Bounded Health",
"events": ["cohort.uploaded", "export.ready", "simulation.completed"],
"signingSecret": "whsec_...",
"status": "active"
}
⚠️ Copy
signingSecretnow! Like API keys, it is shown once. You will need it to verify webhook signatures.
Step 5: Send a test webhook
Verify your endpoint receives events correctly:
curl -X POST "$MT_HOST/api/employer/webhooks/<WEBHOOK_ID>/test" \
-H "x-api-key: $MT_API_KEY" \
-H "x-api-version: 2026-02-01"
Expected response:
{
"success": true,
"statusCode": 200,
"latencyMs": 142
}
Step 6: Verify webhook signatures
Every webhook delivery includes an HMAC-SHA256 signature. Always verify it before processing.
Node.js / Express handler:
import crypto from "crypto";
import express from "express";
const app = express();
// IMPORTANT: Use raw body for signature verification
app.post(
"/webhooks/Bounded Health",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-webhook-signature"] as string;
const rawBody = req.body.toString("utf8");
// Compute expected signature
const expected = `sha256=${crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex")}`;
// Timing-safe comparison to prevent timing attacks
const isValid =
signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!isValid) {
console.error("Invalid webhook signature — rejecting");
return res.status(401).send("Invalid signature");
}
// Parse and process the verified payload
const event = JSON.parse(rawBody);
console.log(`Received event: ${event.event}`, event.data);
// Always respond 200 quickly — process async if needed
res.status(200).send("OK");
}
);
app.listen(3001, () => console.log("Webhook receiver running on :3001"));
Key headers to inspect:
| Header | Purpose |
|---|---|
x-webhook-signature | HMAC-SHA256 signature for verification |
x-webhook-id | Unique delivery ID (use for idempotency) |
x-webhook-event | Event type (e.g., cohort.uploaded) |
x-webhook-timestamp | ISO timestamp of the event |
What comes next
| Goal | Guide |
|---|---|
| Sync employee roster from your HRIS | RECIPES.md → HRIS Roster Sync |
| Export patient data for analytics | RECIPES.md → Bulk FHIR Export |
| Set up SSO with Okta or Azure AD | RECIPES.md → SSO Setup |
| Troubleshoot errors | TROUBLESHOOTING.md |
| Full API key reference | 01-API-KEY-AUTHENTICATION.md |
| Full webhook reference | 02-OUTBOUND-WEBHOOKS.md |
| Full FHIR reference | 03-FHIR-HL7-INTEROPERABILITY.md |
| OpenAPI spec (machine-readable) | /api/openapi |