Migrate from Relu Engine
A quick-reference guide for integrators moving from Relu Engine (v2) to Relu Automate.
Relu Automate is the successor to Relu Engine. If you're already integrated with Engine, this page maps your existing calls onto Automate's service-based API.
Why migrate
- Service-based API. Automate uses tailored services, each with its own input/output/parameter schema, instead of a generic job router. You target only what you want.
- Improved AI. Segmentation, registration, and dentition models are more accurate, especially on challenging cases.
- Better observability. Clearer failure reporting and logs so issues surface faster.
API base URL
https://api.automate.relu.aiAuthentication
Authenticate with an API token in the X-API-Key header:
X-API-Key: <your_api_token>See API keys for how to create a token and request API access for your organization.
Terminology mapping
| Engine | Automate |
|---|---|
POST /job | POST /orders with service_id |
externalJobId | order_name |
inputFiles.cbct | input_data.volume |
inputFiles.ios_upper | input_data.upper_jaw |
inputFiles.ios_lower | input_data.lower_jaw |
outputFiles.meshes[] | output_data.{structure_name} |
finishWebhook | callback_url |
GET /pollJobResults?jobId= | POST /orders/job-statuses, then GET /orders/{id}?include_output_download_urls=true |
The poll_status endpoint is deprecated
Replace GET /orders/{order_id}/poll_status with POST /orders/job-statuses.
After the order reaches Done, fetch the order with
include_output_download_urls=true to get its output files.
Most per-service params kept their names
Most service-specific parameters kept the same name between Engine and
Automate. To see the exact schema for the service you're migrating, fetch GET /services/{id}, or open three-dots menu → View API Example on the service
card in the platform UI for a copy-paste snippet.
Field reference
service_id, the service UUID fromGET /services.order_name, any string, doesn't need to be unique.callback_url, optional webhook URL; see Callbacks.- Input fields (under
input_data.*):external_download_url, where Relu downloads the input from.extension, file extension (same extensions as Engine v2).
- Output fields (under
output_data.*):external_upload_url, where Relu uploads the result to.display_name, optional custom filename (no extension).
- Parameter fields (under
parameter_values.*): every service has its ownparameter_valuesschema. Use View API Example orGET /services/{id}to get the exact keys.
Only request what you use
If you don't need a specific output, omit it from output_data. Automate
won't compute outputs you don't request, keeps your orders fast and cheap.
Example: creating an order (Python)
import requests
API_BASE = "https://api.automate.relu.ai"
headers = {"X-API-Key": "your-api-token"}
order_data = {
"service_id": "<service-uuid from GET /services>",
"order_name": "case-001",
"callback_url": "https://your-server.com/webhook",
"input_data": {
"volume": {
"external_download_url": "https://your-storage.com/scan.dcm",
"extension": ".dcm",
}
},
"output_data": {
# Optional: per-output external_upload_url. Use View API Example for
# the available output keys.
},
"parameter_values": {
# ... every service has its own parameters
},
}
response = requests.post(f"{API_BASE}/orders", json=order_data, headers=headers)
order = response.json()
print("Order ID:", order["id"])Polling order status
Send between 1 and 100 valid order IDs per request. The API returns 422 for an
empty list, more than 100 IDs, or a malformed ID.
import time
order_id = order["id"]
while True:
response = requests.post(
f"{API_BASE}/orders/job-statuses",
headers=headers,
json={"order_ids": [order_id]},
)
response.raise_for_status()
result = response.json()
order_status = result["statuses"].get(order_id)
if order_status is None:
error = next(
(item for item in result["errors"] if item["order_id"] == order_id),
None,
)
code = error["code"] if error else "unknown_error"
raise RuntimeError(f"Order status is unavailable: {code}")
main_job = order_status["main_job"]
if main_job is None:
time.sleep(30)
continue
job_status = main_job["job_status"]
if job_status == "Done":
break
if job_status in ("Failed", "Cancelled"):
raise RuntimeError(f"Order ended with status {job_status}")
time.sleep(30)After the order reaches Done, fetch the outputs and their temporary download
URLs:
completed_order = requests.get(
f"{API_BASE}/orders/{order_id}",
headers=headers,
params={"include_output_download_urls": True},
)
completed_order.raise_for_status()
for output in completed_order.json()["output_files"]:
if output["status"] == "Available":
print(output["name"], output["download_url"])If you also need percentages, use the progress endpoint:
status_and_progress = requests.post(
f"{API_BASE}/orders/progress",
json={"order_ids": ["id-1", "id-2", "id-3"]},
headers=headers,
).json()See Poll vs webhook for the recommended production pattern.
Quality improvements
In standard cases, segmentation quality matches Engine v2. The real gains show up on hard cases, complex anatomy, low-contrast scans, thin structures. Automate produces cleaner boundaries and fewer artifacts on:
- Registration on low-quality scans
- Dentition segmentation on crowded/overlapping cases
- IOS segmentation with noise or artifacts
- Mandible and skull segmentation in difficult volumes
Next steps
- API integration quickstart, the full first-order walkthrough, in Automate terms
- Services, how the service model works
- API reference, every endpoint for every service
Support
Moving large volumes? Email support@relu.ai, we'll help you set up your service, configure parameters, and get the integration running smoothly.