Multiple10 min5 steps
Stream SOAP Notes with SSE
Enable Server-Sent Events to display each SOAP section as it is generated, delivering a real-time experience.
1
Enable streaming
Use the streaming endpoint
POST /v1/stream/note instead of /v1/note. The request body is the same — the API responds with text/event-stream instead of JSON.Terminal
curl -N -X POST https://api.soapnoteapi.com/v1/stream/note \
-H "Authorization: Bearer snapi_sk_test_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"transcript": "Patient is a 38-year-old female presenting for follow-up...",
"specialty": "nurse_practitioner"
}'2
Parse SSE events in Python
Set
stream=True on the requests call and iterate over lines. Each SSE event has a data: prefix containing a JSON object with section and content fields.Python
import os
import json
import requests
api_key = os.environ["SOAPNOTEAPI_KEY"]
response = requests.post(
"https://api.soapnoteapi.com/v1/stream/note",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"Accept": "text/event-stream",
},
json={
"transcript": "Patient is a 38-year-old female presenting for follow-up...",
"specialty": "nurse_practitioner",
},
stream=True,
)
for line in response.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
payload = line[len("data: "):]
if payload == "[DONE]":
print("\nStream complete.")
break
event = json.loads(payload)
# event: { "section": "subjective", "content": "Patient is a..." }
print(f"[{event['section']}] {event['content']}", end="", flush=True)3
Parse SSE events in Node.js
Use the fetch response body as a readable stream. Decode chunks as UTF-8 text and split on newlines to extract SSE data lines.
JavaScript
const apiKey = process.env.SOAPNOTEAPI_KEY;
const response = await fetch("https://api.soapnoteapi.com/v1/stream/note", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Accept": "text/event-stream",
},
body: JSON.stringify({
transcript: "Patient is a 38-year-old female presenting for follow-up...",
specialty: "nurse_practitioner",
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() ?? "";
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
const payload = line.slice("data: ".length);
if (payload === "[DONE]") {
console.log("\nStream complete.");
break;
}
const event = JSON.parse(payload);
process.stdout.write(`[${event.section}] ${event.content}`);
}
}4
Parse SSE events in the browser
In a browser context you can use the Fetch API with a
ReadableStream. The pattern is similar to the Node.js version, but you update the DOM instead of writing to stdout.JavaScript
async function streamNote(transcript, specialty, onChunk) {
const response = await fetch("https://api.soapnoteapi.com/v1/stream/note", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Accept": "text/event-stream",
},
body: JSON.stringify({ transcript, specialty }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() ?? "";
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
const payload = line.slice("data: ".length);
if (payload === "[DONE]") return;
const event = JSON.parse(payload);
onChunk(event.section, event.content);
}
}
}
// Usage
streamNote(transcript, "nurse_practitioner", (section, content) => {
document.getElementById(section).textContent += content;
});5
Build a real-time UI with React
Combine the streaming pattern with React state to progressively render each SOAP section as it arrives.
JavaScript
import { useState, useCallback } from "react";
function useSoapStream() {
const [sections, setSections] = useState({
subjective: "",
objective: "",
assessment: "",
plan: "",
});
const [isStreaming, setIsStreaming] = useState(false);
const generate = useCallback(async (transcript, specialty) => {
setIsStreaming(true);
setSections({ subjective: "", objective: "", assessment: "", plan: "" });
const response = await fetch("https://api.soapnoteapi.com/v1/stream/note", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Accept": "text/event-stream",
},
body: JSON.stringify({ transcript, specialty }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() ?? "";
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
const payload = line.slice("data: ".length);
if (payload === "[DONE]") break;
const { section, content } = JSON.parse(payload);
setSections((prev) => ({
...prev,
[section]: prev[section] + content,
}));
}
}
setIsStreaming(false);
}, []);
return { sections, isStreaming, generate };
}
// In your component:
// const { sections, isStreaming, generate } = useSoapStream();
// <p>{sections.subjective}</p>
// <p>{sections.objective}</p>
// ...Ready to start building?
Get a free API key and $10 in credit — no credit card required.
Get your free API key