Quick start
A scan workflow, from an empty editor to one triggered run. A POST starts it with a patient id and phone number. The run saves a scan link, pauses until the patient finishes or 30 minutes pass, then sends a notification.
1. Create the loop
From your loops list, create a loop and pick New Workflow Loop. Name it health-scan.
You’ll land in the editor with a starter file. Replace it with the workflow below.
2. Write the workflow
import { workflow } from "@loops/sdk";
type ScanRequest = { patientId: string; phoneNumber: string };
export const healthScanWorkflow = workflow<ScanRequest>({
id: "health-scan",
execute: async ({ step, event }) => {
const { patientId, phoneNumber } = event.body;
await step.do("Generate a health scan", async ({ ctx }) => {
await ctx.FACIAL_SCAN.create({
metadata: { patientId, phoneNumber },
});
});
const scan = await step.waitForScan({ timeout: "30 minutes" });
await step.do("Send a notification", async () => {
await fetch("https://api.example.com/send-notification", {
method: "POST",
body: JSON.stringify({
patientId,
phoneNumber,
scanResult: scan.results,
reportUrl: await scan.pdfUrl(),
}),
});
});
},
});Three pieces are doing the work:
workflow<ScanRequest>({ id, execute })is the loop.idis its name.event.bodyis the JSON you POST, typed asScanRequest.step.dosaves the scan onceFACIAL_SCAN.createfinishes. A later replay does not create it again. The same is true of the notification step. Tools are onctx, andctxonly exists inside the step.step.waitForScanpauses the run. It resumes with aScanhandle when the patient finishes, or it throws after 30 minutes.
metadata is stored on the scan and comes back with the results, so the session already knows which patient it belongs to.
3. Allow the host
fetch only reaches hosts the loop allows. Open the loop’s Controls, add api.example.com under Allowed hosts, and save. See Controls.
4. Deploy
Click Deploy. The platform stores a new version, marks it active, and opens the loop overview. The next run uses that version. A run already in flight keeps the version it started with.
5. Trigger a run
From the UI: click Run and paste this body.
{ "patientId": "pat_18", "phoneNumber": "+15551234567" }From the API: mint a token under Settings → API tokens, then POST to the loop. The URL is on the loop’s Access dialog.
curl -X POST https://api.ollie.health/loop/$ORG_ID/$LOOP_ID \
-H "Authorization: Bearer $LOOPS_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "patientId": "pat_18", "phoneNumber": "+15551234567" }'The JSON body becomes event.body. The response includes a runId. Because this loop calls FACIAL_SCAN.create, it also includes a scanUrl you can send to the patient. The scan session exists before execute starts.
6. Read the run
Open the run from Runs. You’ll see the steps in order:
- Generate a health scan — saved once
createreturns. - wait-for-scan — paused until the patient finishes, or until 30 minutes pass. The summary and the PDF are generated as part of it.
- Send a notification — runs after the wait, with the results and the PDF url.
The run’s input is the POST body. Logs are every console.* from the loop.
Where to go next
- What is a workflow — steps, waits, and runs.
- Triggering a run — the POST, the token, and the response.
- Calling a workflow — start this workflow from an agent.