ReluAutomate
Core concepts

Orders

An order is a request to execute a service. It tracks inputs, parameters, and outputs through the service's lifecycle.

An order is a single execution of a service. Create one with POST /orders and Relu:

  1. Downloads the input files (from presigned URLs you provide, or from platform-uploaded file IDs)
  2. Queues the order for processing by our AI
  3. Runs the service
  4. Stores the outputs and optionally uploads them to presigned URLs you provide

Creating an order

Use the generic route POST /orders and pass the service's UUID as service_id in the body:

{
  "service_id": "<service-uuid from GET /services>",
  "order_name": "case-001",
  "input_data": {
    "lower_jaw": { "external_download_url": "...", "extension": ".stl" }
  },
  "parameter_values": {
    /* service-specific */
  },
  "callback_url": "https://your-app.com/relu-webhook"
}

The exact input_data, output_data, and parameter_values keys depend on which service you're calling — fetch them from GET /services/{id}, or open the three-dots menu → View API Example on the service card in the platform UI to copy a ready-to-run snippet.

Instead of (or in addition to) listing parameter_values, you can reference a saved preset by passing preset_id. The order inherits the preset's parameters and output settings; any parameter_values you also send override the preset for those keys.

Per-service routes will be deprecated

Each service used to have a typed dedicated route (POST /orders/model-builder-v1, POST /orders/dies-v1, etc.). They still work and remain in the OpenAPI spec for existing integrations, but they are slated for deprecation. Use POST /orders for new integrations.

Lifecycle

The order's main job moves through main_job.job_status:

  • Submitted, accepted and queued/running
  • Done, outputs are available
  • Failed, something went wrong — see Order processing errors for the fields to surface to your users
  • Cancelled, cancelled before it finished

Use POST /orders/job-statuses when you need to poll for completion, or receive a callback. Status polling reads from Automate's database and uses fewer resources than progress polling. 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. Use POST /orders/progress only if your UI needs a progress percentage.

Approval status

Approval status is separate from main_job.job_status. Set it after the main job reaches Done:

PUT /orders/{order_id}/status?status=Approved

Scope required

This endpoint requires the following scope: update:orders

The request has no JSON body. The API user also needs order:approve permission on the order. Valid values are:

  • Approved, accept the completed result.
  • Rejected, reject the result without creating feedback or a refund request.
  • Unapproved, reset an approval or rejection while keeping the status history.

You can move directly between any of these values. Each request appends a status record, and the latest record is the order's current approval status. Changing the status emits an order.status callback.

To update several orders, use the bulk route. It checks each order separately and returns the successful updates and failures in one response:

PATCH /orders/status?status=Approved
Content-Type: application/json

{ "order_ids": ["<order_id_a>", "<order_id_b>"] }

Use POST /feedback/ when a rejection should also record feedback or request a refund.

Tracking progress

Start with POST /orders/job-statuses if you only need to know whether orders are finished. It reads from Automate's database, so it is faster and uses fewer resources. Each request accepts between 1 and 100 valid order IDs.

If your UI needs a progress percentage, use POST /orders/progress. This endpoint may contact processing engines to refresh stale progress values, which uses additional resources. Pass the order IDs in one request:

// POST /orders/progress
{ "order_ids": ["<order_id_a>", "<order_id_b>"] }

The response maps each order ID to its progress info:

{
  "progress": {
    "<order_id_a>": {
      "order_id": "<order_id_a>",
      "main_job": {
        "job_status": "Submitted",
        "end_timestamp": null
      },
      "progress_job": {
        "job_type": "Main",
        "job_status": "Submitted",
        "end_timestamp": null
      },
      "progress": 42,
      "error": null
    },
    "<order_id_b>": {
      "order_id": "<order_id_b>",
      "main_job": {
        "job_status": "Done",
        "end_timestamp": "2026-09-02T10:24:00Z"
      },
      "progress_job": {
        "job_type": "Recompute",
        "job_status": "Submitted",
        "end_timestamp": null
      },
      "progress": null,
      "error": null
    }
  }
}

Reading the response:

  • main_job.job_status is the authoritative state of the original order.
  • progress_job identifies the Main or Recompute job described by progress.
  • progress is a number: render it as a percentage. A processing job is held at 99 until it finishes. A terminal job can report 100.
  • progress is null: the order is queued, or there's no estimate yet. Show "Queued", a spinner, or 0% instead of treating it as a percentage.
  • progress_job is null: an accessible order has no Main or active Recompute job. It remains in the response even when no percentage is available.
  • The order ID is absent from progress: the order does not exist or you cannot access it. This endpoint does not return an errors list. Use POST /orders/job-statuses if you need an error for each omitted ID.

Progress caps at 99% until Done

The engine reaches 100% slightly before Relu finishes ingesting the outputs, so a still-processing job is capped at 99. Treat main_job.job_status == "Done" (or the callback) — not progress == 100 — as the signal that outputs are ready.

Progress tells you how far along an order is, not whether it's finished. To detect completion, use a webhook or poll the order's status.

Order permissions

By default, orders are visible to the organization that created them. You can share orders with individual users or via public links. Orders are always billed to the owner organization, no matter who else has access.

On this page