Skip to Content
External systems

Calling an external system

A loop calls another system with fetch: a practice system, a lab, a medical aid. Add the system’s host to the loop’s allowed hosts first. Any other host throws This loop cannot reach … Add it under Controls → Allowed hosts.

Keep credentials in variables and secrets, not in the code.

From a workflow

Put the call inside a step.do. The step saves what you return, and a replay uses that value instead of calling again.

import { workflow } from "@loops/sdk"; type Booking = { patientId: string; date: string }; export const bookFollowUpWorkflow = workflow<Booking>({ id: "book-follow-up", execute: async ({ step, event, env }) => { const { patientId, date } = event.body; return step.do("Book the appointment", async () => { const response = await fetch( "https://api.practice.example.com/v1/appointments", { method: "POST", headers: { "content-type": "application/json", Authorization: `Bearer ${env.PRACTICE_API_KEY}`, }, body: JSON.stringify({ patientId, date }), }, ); if (!response.ok) { throw new Error(`Booking failed: ${response.status}`); } return response.json(); }); }, });

Throwing on a non-2xx response fails the step, and the platform retries it once.

From an agent

The model can’t call fetch itself. Wrap the call in a tool and pass the tool to submit. The model decides when to book, and execute makes the request with the input the model gave.

tools.ts
import { defineTool, Type } from "@loops/sdk"; export const bookAppointment = defineTool({ name: "book_appointment", description: "Book a follow-up appointment at the practice", parameters: Type.Object({ patientId: Type.String(), date: Type.String(), }), execute: async (input) => { const response = await fetch( "https://api.practice.example.com/v1/appointments", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input), }, ); if (!response.ok) { throw new Error(`Booking failed: ${response.status}`); } return response.json(); }, });
agent.ts
import { chatAgent, model } from "@loops/sdk"; import { bookAppointment } from "./tools"; export const healthChatAgent = chatAgent({ id: "health-chat", execute: async ({ submit, messages }) => submit({ messages, tools: [bookAppointment], model: model("gpt-4o-mini"), }), });

A tool’s execute gets only the model’s input. To use a secret, define the tool inside the agent’s execute, where env is in scope, or start a workflow from it. See Tools and Calling a workflow.

Last updated on