Skip to main content
In this guide, you’ll trigger a Friday workflow from your application, stream its progress in real time, and optionally cancel it.

Prerequisites

  • Friday Studio installed and running
  • At least one space loaded with a signal configured
  • The daemon API is available at http://localhost:18080
Run curl http://localhost:18080/api/workspaces to see your loaded spaces and their IDs. Each space’s signals object shows what signals are available and what payload fields they expect.

Trigger a signal

Every workflow starts with a signal. Send a POST request with a payload and Friday runs the job.

Fire and wait

Send a POST and block until the job completes:
curl -X POST http://localhost:18080/api/workspaces/{workspaceId}/signals/{signalId} \
  -H 'Content-Type: application/json' \
  -d '{"payload": {"key": "value"}}'
const response = await fetch(
  "http://localhost:18080/api/workspaces/{workspaceId}/signals/{signalId}",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ payload: { key: "value" } }),
  }
);

const result = await response.json();
console.log(result.sessionId); // use this to check status
import httpx

response = httpx.post(
    "http://localhost:18080/api/workspaces/{workspaceId}/signals/{signalId}",
    json={"payload": {"key": "value"}},
)
response.raise_for_status()
print(response.json()["sessionId"])
Response:
{
  "message": "Signal completed",
  "status": "completed",
  "workspaceId": "my-space",
  "signalId": "my-signal",
  "sessionId": "sess_abc123"
}

Stream progress in real time

Add Accept: text/event-stream to receive a live SSE stream as the job executes:
curl -N -X POST http://localhost:18080/api/workspaces/{workspaceId}/signals/{signalId} \
  -H 'Content-Type: application/json' \
  -H 'Accept: text/event-stream' \
  -d '{"payload": {"key": "value"}}'
const response = await fetch(
  "http://localhost:18080/api/workspaces/{workspaceId}/signals/{signalId}",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "text/event-stream",
    },
    body: JSON.stringify({ payload: { key: "value" } }),
  }
);

const reader = response.body!.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  for (const line of decoder.decode(value).split("\n")) {
    if (line.startsWith("data: ")) {
      const data = line.slice(6);
      if (data === "[DONE]") break;
      console.log(JSON.parse(data));
    }
  }
}
import httpx

with httpx.stream(
    "POST",
    "http://localhost:18080/api/workspaces/{workspaceId}/signals/{signalId}",
    json={"payload": {"key": "value"}},
    headers={"Accept": "text/event-stream"},
) as response:
    response.raise_for_status()
    for line in response.iter_lines():
        if line.startswith("data: ") and line[6:] != "[DONE]":
            print(line[6:])
Event stream:
data: {"type":"data-session-start","data":{"sessionId":"sess_abc123"}}

data: {"type":"text-delta","delta":"Fetching emails..."}

data: {"type":"job-complete","data":{"success":true,"sessionId":"sess_abc123","status":"completed"}}

data: [DONE]

Check run status

Use the sessionId from the trigger response to check on the run:
curl http://localhost:18080/api/sessions/sess_abc123
const session = await fetch(
  "http://localhost:18080/api/sessions/sess_abc123"
).then(r => r.json());

console.log(session.status); // "completed", "running", or "failed"
import httpx

session = httpx.get("http://localhost:18080/api/sessions/sess_abc123").json()
print(session["status"])

Cancel a running job

If you need to stop a job mid-execution:
curl -X DELETE http://localhost:18080/api/sessions/sess_abc123
await fetch("http://localhost:18080/api/sessions/sess_abc123", {
  method: "DELETE",
});
import httpx

httpx.delete("http://localhost:18080/api/sessions/sess_abc123")

Next steps

API reference

Full endpoint reference for every API operation.

Signals

Signal types, payload schemas, and webhook configuration.