API Reference

Every endpoint of the RamAIn Workflows API, from launching runs and polling status to results, events, human input, and webhooks.

All endpoints live under the versioned base URL and require a workspace API key as a Bearer token:

Base URL: https://api.ramain.ai/api/v1
Header:   Authorization: Bearer rmn_live_...

Examples below use a workflow with a single required input, order_number, which is the same shape the in-portal API docs generate for each of your published workflows:

Per-workflow API docs: endpoint, input table, and copy-ready snippets

Launch a run

POST /automations/{workflowId}/runs

Launches a run of a Published workflow. Returns 202 Accepted immediately; the run executes asynchronously. Requires the workflows:run scope.

Request body

FieldTypeRequiredDescription
inputsobjectYesThe workflow's input fields, validated against its input contract. Unknown keys are rejected.
metadataobjectNoArbitrary key-value pairs stored with the run (e.g. correlation_id).
callback_urlstringNoPublic HTTPS webhook URL. RamAIn POSTs the terminal run payload here when execution finishes.
idempotency_keystringNoPass the same key on retries to avoid launching duplicate runs.
modelstringNoOverride the RamAIn model used for this run.
curl -X POST https://api.ramain.ai/api/v1/automations/wf_audit_zoho/runs \
  -H "Authorization: Bearer rmn_live_xJ4..." \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": { "order_number": "JODL-2041" },
    "metadata": { "correlation_id": "erp-58812" },
    "callback_url": "https://example.com/hooks/ramain",
    "idempotency_key": "erp-58812-attempt-1"
  }'

Response: 202 Accepted

{
  "run_id": "run_9f3ka72",
  "workflow_id": "wf_audit_zoho",
  "status": "pending",
  "created_at": "2026-07-21T10:30:00Z",
  "status_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72",
  "result_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72/result",
  "events_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72/events",
  "queue": { "position": 0 }
}

Passwords are never inputs

Saved Passwords a workflow uses are resolved inside the workspace at runtime. They never appear in the input contract and can't be passed through the API.

Get run status

GET /runs/{runId}

Returns the run envelope. Requires the runs:read scope.

{
  "run_id": "run_9f3ka72",
  "workflow_id": "wf_audit_zoho",
  "status": "running",
  "created_at": "2026-07-21T10:30:00Z",
  "status_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72",
  "result_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72/result",
  "events_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72/events"
}

When a run pauses for a person, the envelope carries a description of what's needed and where to answer:

{
  "run_id": "run_9f3ka72",
  "status": "waiting_for_human",
  "human_action": "Approve the order total before submission",
  "resume_url": "https://api.ramain.ai/api/v1/runs/run_9f3ka72/human-input"
}

Run statuses

StatusMeaning
pendingAccepted, not yet picked up.
queuedWaiting behind other runs in the workspace queue.
runningExecuting now.
waiting_for_humanPaused for a person. See human_action and resume_url.
completedFinished successfully; result is available.
failedFinished with an error.
dead_letterFailed and parked in the review queue for inspection or retry.

Get run result

GET /runs/{runId}/result

Returns 202 while the run is still in progress. Once the run is terminal, it returns the structured outputs, including any files the run produced.

{
  "run_id": "run_9f3ka72",
  "status": "completed",
  "outputs": {
    "zoho_order_id": "SO-00871",
    "order_total": "1,240.00 EUR",
    "files": [
      {
        "name": "order-confirmation.pdf",
        "contentType": "application/pdf",
        "downloadUrl": "https://api.ramain.ai/api/v1/runtime-files/f_28ab41/download?token=..."
      }
    ]
  }
}

Downloading files

Each entry in outputs.files[] carries a signed downloadUrl. The link is self-authenticating, so no API key is needed on the download itself; you can hand the URL to a browser, a signed-URL-aware client, or plain curl:

# Grab the first output file from the result
RESULT=$(curl -s https://api.ramain.ai/api/v1/runs/run_9f3ka72/result \
  -H "Authorization: Bearer rmn_live_xJ4...")

URL=$(echo "$RESULT" | jq -r '.outputs.files[0].downloadUrl')
NAME=$(echo "$RESULT" | jq -r '.outputs.files[0].name')

curl -o "$NAME" "$URL"

Signed links expire, so download promptly after fetching the result rather than storing the URL long-term. If a link has expired, fetch the result again for a fresh one.

List run events

GET /runs/{runId}/events

Returns the public step events of a run as a JSON list. This is the endpoint to build progress UIs on: it shows what the run is doing without you having to poll the status envelope aggressively.

{
  "run_id": "run_9f3ka72",
  "events": [
    { "at": "2026-07-21T10:30:04Z", "type": "run.started" },
    { "at": "2026-07-21T10:30:12Z", "type": "step.completed", "step": "Look up order JODL-2041" },
    { "at": "2026-07-21T10:31:40Z", "type": "run.completed" }
  ]
}

Resume human input

POST /runs/{runId}/human-input

Resumes a run in waiting_for_human by answering on the caller's behalf. Requires the workflows:run scope. Use the resume_url from the status envelope, or build the path from the run_id.

Request body

FieldTypeRequiredDescription
responsestringYesThe answer to the question in human_action, in plain language.
curl -X POST https://api.ramain.ai/api/v1/runs/run_9f3ka72/human-input \
  -H "Authorization: Bearer rmn_live_xJ4..." \
  -H "Content-Type: application/json" \
  -d '{ "response": "Approved. The total of 1,240.00 EUR is correct." }'

The run picks up where it paused, with your response injected as if a teammate had answered in the portal. Poll the status afterwards as usual; the run transitions back through running on its way to a terminal state.

Webhook payload

If you passed a callback_url at launch, RamAIn POSTs to it once the run reaches a terminal state, with User-Agent: RamAIn-Workflow-API/1.0:

{
  "type": "workflow.run.completed",
  "run": {
    "run_id": "run_9f3ka72",
    "workflow_id": "wf_audit_zoho",
    "status": "completed"
  },
  "result": {
    "outputs": { "zoho_order_id": "SO-00871" }
  }
}

Verify webhooks server-side

Treat the webhook as a notification, not as truth. On receipt, fetch the run's status_url from your server with your API key and act on that response.

Example receiver

A minimal receiver that verifies the notification before acting on it:

Tab: Node.js (Express)

import express from "express";

const app = express();
app.use(express.json());

const HEADERS = { Authorization: "Bearer rmn_live_xJ4..." };

app.post("/hooks/ramain", async (req, res) => {
  // Acknowledge fast; do the work after responding.
  res.sendStatus(200);

  const runId = req.body?.run?.run_id;
  if (!runId) return;

  // Verify against the API instead of trusting the payload.
  const status = await (
    await fetch(`https://api.ramain.ai/api/v1/runs/${runId}`, { headers: HEADERS })
  ).json();

  if (status.status === "completed") {
    const result = await (
      await fetch(`https://api.ramain.ai/api/v1/runs/${runId}/result`, { headers: HEADERS })
    ).json();
    console.log("Run finished:", result.outputs);
  }
});

app.listen(3000);

Tab: Python (FastAPI)

import requests
from fastapi import BackgroundTasks, FastAPI, Request

app = FastAPI()

BASE = "https://api.ramain.ai/api/v1"
HEADERS = {"Authorization": "Bearer rmn_live_xJ4..."}


def process_run(run_id: str) -> None:
    # Verify against the API instead of trusting the payload.
    status = requests.get(f"{BASE}/runs/{run_id}", headers=HEADERS).json()
    if status["status"] == "completed":
        result = requests.get(f"{BASE}/runs/{run_id}/result", headers=HEADERS).json()
        print("Run finished:", result["outputs"])


@app.post("/hooks/ramain")
async def ramain_hook(request: Request, tasks: BackgroundTasks):
    payload = await request.json()
    run_id = payload.get("run", {}).get("run_id")
    if run_id:
        # Acknowledge fast; do the work after responding.
        tasks.add_task(process_run, run_id)
    return {"ok": True}

Retry a dead-lettered run

Runs that fail can land in a review queue. After inspecting (or fixing the underlying cause), retry them:

POST /runs/{runId}/dead-letter/retry

Errors

HTTPCodeMeaning
400INVALID_INPUTSInputs failed validation against the workflow's contract (missing required field or unknown key).
402(none)Launch blocked by billing. The workspace has an outstanding balance or no credits.
404WORKFLOW_NOT_FOUNDNo workflow with that ID is visible to this key.
409WORKFLOW_NOT_PUBLISHEDThe workflow exists but is a draft. Publish it first.
413(none)An attachment in the request is too large.
429(none)The workspace run queue is full. Retry with backoff.

Keeping the contract in sync

Every published workflow's API contract mirrors its Input block: add or rename an input in the editor, publish, and the endpoint's parameters update on the next publish. The in-portal API Docs page always shows the current contract with copy-ready JSON and curl snippets.

Was this page helpful?