import httpx
import json
DEEPRAILS_API_KEY = "YOUR_API_KEY"
workflow_id = "wkfl_xxxxxxxxxxxx"
url = f"https://api.deeprails.com/defend/{workflow_id}/events?stream=true"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {DEEPRAILS_API_KEY}",
}
payload = {
"model_input": {"prompt": "Christmas Day was filled with festive broadcasting but what was 2025’s most-watched programme in the UK?"},
"model_output": "The Celebrity Traitors.",
"model_used": "gpt-4",
"run_mode": "precision",
}
with httpx.stream("POST", url, json=payload, headers=headers, timeout=120.0) as response:
event_type = None
data_buffer = []
for line in response.iter_lines():
if line.startswith("event:"):
event_type = line[6:].strip()
elif line.startswith("data:"):
data_buffer.append(line[5:].strip())
elif line == "" and event_type:
data = json.loads("".join(data_buffer))
if event_type == "token":
print(data["content"], end="", flush=True)
elif event_type == "error":
print(f"Error: {data['message']}")
break
event_type = None
data_buffer = []const DEEPRAILS_API_KEY = "YOUR_API_KEY";
const workflowId = "wkfl_xxxxxxxxxxxx";
const response = await fetch(
`https://api.deeprails.com/defend/${workflowId}/events?stream=true`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${DEEPRAILS_API_KEY}`,
},
body: JSON.stringify({
model_input: { prompt: "Christmas Day was filled with festive broadcasting but what was 2025’s most-watched programme in the UK?" },
model_output: "The Celebrity Traitors.",
model_used: "gpt-4",
run_mode: "precision",
}),
}
);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let currentEvent = "";
let dataBuffer = [];
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("event:")) {
currentEvent = line.slice(6).trim();
} else if (line.startsWith("data:")) {
dataBuffer.push(line.slice(5).trim());
} else if (line === "" && currentEvent) {
const data = JSON.parse(dataBuffer.join(""));
if (currentEvent === "token") {
process.stdout.write(data.content);
} else if (currentEvent === "error") {
console.error(`Error: ${data.message}`);
break;
}
currentEvent = "";
dataBuffer = [];
}
}
}
curl -N \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_input": {"prompt": "Christmas Day was filled with festive broadcasting but what was 2025’s most-watched programme in the UK?"},
"model_output": "The Celebrity Traitors.",
"model_used": "gpt-4",
"run_mode": "precision"
}' \
"https://api.deeprails.com/defend/wkfl_xxxxxxxxxxxx/events?stream=true"
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.deeprails.com/defend/{workflow_id}/events?stream=true",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model_input' => [
],
'model_output' => '<string>',
'model_used' => '<string>',
'nametag' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.deeprails.com/defend/{workflow_id}/events?stream=true"
payload := strings.NewReader("{\n \"model_input\": {},\n \"model_output\": \"<string>\",\n \"model_used\": \"<string>\",\n \"nametag\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.deeprails.com/defend/{workflow_id}/events?stream=true")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model_input\": {},\n \"model_output\": \"<string>\",\n \"model_used\": \"<string>\",\n \"nametag\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.deeprails.com/defend/{workflow_id}/events?stream=true")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model_input\": {},\n \"model_output\": \"<string>\",\n \"model_used\": \"<string>\",\n \"nametag\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"event": "token",
"data": {
"content": "The Celebrity"
}
}Stream a Workflow Event (Optimized)
Use this endpoint to submit a model input and output pair to a workflow for evaluation with streaming responses.
import httpx
import json
DEEPRAILS_API_KEY = "YOUR_API_KEY"
workflow_id = "wkfl_xxxxxxxxxxxx"
url = f"https://api.deeprails.com/defend/{workflow_id}/events?stream=true"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {DEEPRAILS_API_KEY}",
}
payload = {
"model_input": {"prompt": "Christmas Day was filled with festive broadcasting but what was 2025’s most-watched programme in the UK?"},
"model_output": "The Celebrity Traitors.",
"model_used": "gpt-4",
"run_mode": "precision",
}
with httpx.stream("POST", url, json=payload, headers=headers, timeout=120.0) as response:
event_type = None
data_buffer = []
for line in response.iter_lines():
if line.startswith("event:"):
event_type = line[6:].strip()
elif line.startswith("data:"):
data_buffer.append(line[5:].strip())
elif line == "" and event_type:
data = json.loads("".join(data_buffer))
if event_type == "token":
print(data["content"], end="", flush=True)
elif event_type == "error":
print(f"Error: {data['message']}")
break
event_type = None
data_buffer = []const DEEPRAILS_API_KEY = "YOUR_API_KEY";
const workflowId = "wkfl_xxxxxxxxxxxx";
const response = await fetch(
`https://api.deeprails.com/defend/${workflowId}/events?stream=true`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${DEEPRAILS_API_KEY}`,
},
body: JSON.stringify({
model_input: { prompt: "Christmas Day was filled with festive broadcasting but what was 2025’s most-watched programme in the UK?" },
model_output: "The Celebrity Traitors.",
model_used: "gpt-4",
run_mode: "precision",
}),
}
);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let currentEvent = "";
let dataBuffer = [];
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("event:")) {
currentEvent = line.slice(6).trim();
} else if (line.startsWith("data:")) {
dataBuffer.push(line.slice(5).trim());
} else if (line === "" && currentEvent) {
const data = JSON.parse(dataBuffer.join(""));
if (currentEvent === "token") {
process.stdout.write(data.content);
} else if (currentEvent === "error") {
console.error(`Error: ${data.message}`);
break;
}
currentEvent = "";
dataBuffer = [];
}
}
}
curl -N \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_input": {"prompt": "Christmas Day was filled with festive broadcasting but what was 2025’s most-watched programme in the UK?"},
"model_output": "The Celebrity Traitors.",
"model_used": "gpt-4",
"run_mode": "precision"
}' \
"https://api.deeprails.com/defend/wkfl_xxxxxxxxxxxx/events?stream=true"
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.deeprails.com/defend/{workflow_id}/events?stream=true",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model_input' => [
],
'model_output' => '<string>',
'model_used' => '<string>',
'nametag' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.deeprails.com/defend/{workflow_id}/events?stream=true"
payload := strings.NewReader("{\n \"model_input\": {},\n \"model_output\": \"<string>\",\n \"model_used\": \"<string>\",\n \"nametag\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.deeprails.com/defend/{workflow_id}/events?stream=true")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model_input\": {},\n \"model_output\": \"<string>\",\n \"model_used\": \"<string>\",\n \"nametag\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.deeprails.com/defend/{workflow_id}/events?stream=true")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model_input\": {},\n \"model_output\": \"<string>\",\n \"model_used\": \"<string>\",\n \"nametag\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"event": "token",
"data": {
"content": "The Celebrity"
}
}Why use streaming?
By default, when you submit a workflow event, the response is delivered all at once after processing completes. Streaming lets you start receiving outputs immediately, before processing is entirely finished — perfect for chat interfaces or any application where perceived latency matters.
How it works
Add stream=true to your request, and you’ll receive a stream of Server-Sent Events instead of a single JSON response.
Streaming is supported on all run modes except precision_max and precision_max_codex.
Note: super_fast does not support Web Search or File Search. If your workflow has these capabilities enabled, either switch to a run mode that supports them (e.g. fast, precision, precision_codex) or edit the workflow to disable Web Search / File Search.
Defend evaluates the model output against your workflow’s guardrails. If the output passes, it streams back the original. If it fails, Defend improves it and streams back the improved version. Either way, you receive a single stream of token events containing the final output — just forward them to your end-user.
Event types
– token: These are the output chunks. Stream them directly to your end-user as they arrive.
– error: This means something went wrong, and will include a message.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
The ID of the workflow to create the event for.
Query Parameters
Enable SSE streaming for real-time token feedback. Supported on all run modes except precision_max and precision_max_codex.
Body
The input provided to the model (e.g., prompt, messages).
The output generated by the model to be evaluated.
The model that generated the output (e.g., "gpt-4", "claude-3").
The evaluation run mode. Streaming is supported on all run modes except precision_max and precision_max_codex. Note: super_fast does not support Web Search or File Search — if your workflow has these enabled, use a different run mode or disable the capability on the workflow.
super_fast, fast, precision, precision_codex Optional tag to identify this event.
Response
A stream of Server-Sent Events delivering the output directly to your end-user.
Each event has an event: type and a data: JSON payload. You'll receive:
– token — Output chunks. Stream these directly to your end-user as they arrive. If the original output passed all guardrails, the tokens contain the original. If improvement was needed, the tokens contain the improved version. Either way, you should forward them.
– error — This means something went wrong and includes a message field.
The response is of type string<sse>.
