Service requests (workflows)

Turn a recurring request - a new laptop, an onboarding, a firewall change - into an offer with fixed steps. Everyone can ask for it in one form; the right teams get their step in the right order, and automation such as n8n can take part.

Overview

A service request offer (the template) describes the steps, who does them, in which order and what the requester has to tell you. A request is one run of an offer. It consists of

WhoDoes what
Designer (role Workflows, or RC Admin)Builds the offers, chooses who may start them, sets up triggers, watches the trigger dashboard.
RequesterStarts a request from an offer they may use, follows it under My service requests.
Team membersWork their step like any task. Finishing it wakes the next step.

1. Design an offer

Open Service Requests → Overview and click New service request offer (you need the role Workflows).

  1. Name and description are what requesters see in the list. Tags help to find the offer.
  2. Who may run it: choose the roles that may start the offer, or leave it open for everybody. The list shows an offer only to people who may start it, and the server checks it again when the form is sent. An RC Admin may always start every offer.
  3. Request intake fields are what the requester fills in: text (optionally limited by a regular expression, e.g. an IP address), number, date or dropdown. All of them are required, and are checked on the server, not only in the browser. The field's name is also a variable for trigger URLs (see below).
  4. Steps: for each step choose the team, a title and description, the estimate, and which step it depends on (none = it starts at once). The estimate also drives the progress bar of the request.
  5. Step fields (per step): values the person working the step must fill in before they can finish it, for example a ticket number or a serial number. A step with an empty step field cannot be finished - not on the Done button and not through the API.
  6. Trigger (per step, optional): an address that is called when the step is finished, see section 5.

Changing an offer does not change requests that are already running: they keep the steps they were started with.

2. Start a request

Click an offer in Service Requests → Overview. Give the request a title and a description, choose the solution (the service it is for) and fill in the request fields.

It is all or nothing: if a field is empty or has the wrong format, you get the reason and nothing has been created. Otherwise you get the master task and every step task; the first steps are active and appear in their teams' pools. Each task gets the usual "task created" entry, and automation is told (section 7).

3. Work the steps

A step is a normal task in its team: it can be taken from the pool, assigned, commented and booked on. It carries the requester's answers in the master task's first comment.

4. Follow your requests

Service Requests → My service requests shows one row per request in two tables: open and finished. A row has

5. Step triggers

A trigger lets another system react when a step is finished: start a provisioning job, create an account, tell a chat channel. Per step you choose how it is sent:

Call before finishingSend as webhook
Sent asGET, right when someone clicks DonePOST with a JSON body, by the scheduler (within about a minute)
The step is doneonly if the address answers 200 within 10 seconds; otherwise it stays open and the person sees whyat once, whatever the receiver does
On failurenothing is retried; press Done againretried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours (six attempts); then it is marked given up and the task gets a note
Signednoyes (X-RC-Signature)
Use it whenthe next step must not start unless the other system has accepted the orderthe other system should just be told, and may be down for a while

Every step that existed before this option behaves as call before finishing.

The address and its variables

Write the address with the field names in angle brackets, for example https://automation.example.com/hook/laptop?size=<size>&ticket=<ticket>. When the trigger runs, each <name> is replaced by the URL-encoded value of that field: the requester's request fields and the step fields filled in so far (a step's own value wins over a request field of the same name).

The address must be http or https without a user name or password, and - unless the instance allows private addresses (setting webhook_allow_private or the environment variable RC_WEBHOOK_ALLOW_PRIVATE=1, for an intranet n8n) - a public one. The check is made again at delivery, and the connection goes to the address that was checked. Up to three redirects are followed in call before finishing mode and each one is checked; the webhook mode follows none.

Anything secret belongs in the signature, not in the address: the address is shown to designers and its query string is never written to the logs or the task history (only scheme, host and path are).

What the webhook carries

POST /hook/laptop HTTP/1.1
Content-Type: application/json
X-RC-Event: workflow.step_trigger
X-RC-Delivery: 5f0c...        (the same on every retry)
X-RC-Attempt: 1
X-RC-Signature: t=1760437200,v1=9b1f...

{ "id": "5f0c...", "event": "workflow.step_trigger", "created": "2026-10-14T10:20:00+00:00",
  "instance": "https://rc.example.com",
  "data": {
    "id": 13541, "title": "Order the laptop", "type": "Service Request", "team_id": 7,
    "workflow": { "request_id": 13538, "template_id": 4, "template": "New laptop",
                  "kind": "step", "step": 2, "steps": 3,
                  "fields": { "size": "M", "ticket": "INC-7" } },
    "trigger": { "request_id": 13538, "step": 2 } } }

Verify the signature before you trust the body. It is the same scheme as for every webhook of the instance: HMAC-SHA256 over t + "." + body with the instance's trigger secret, hex-encoded. Refuse a timestamp that is more than a few minutes old.

# Python
import hmac, hashlib, time
def valid(secret, header, body, tolerance=300):
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > tolerance:
        return False
    expected = hmac.new(secret.encode(), (parts["t"] + ".").encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])
// Node
const crypto = require('crypto');
function valid(secret, header, body, tolerance = 300) {
  const p = Object.fromEntries(header.split(',').map(x => x.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(p.t)) > tolerance) return false;
  const expected = crypto.createHmac('sha256', secret).update(p.t + '.' + body).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(p.v1));
}

The secret is on the trigger dashboard (next section). An RC Admin can create a new one; every receiver must then be given it.

Answer with any 2xx status to confirm. Any other answer, no answer within 10 seconds, or no connection counts as a failed attempt; 410 Gone gives up at once.

6. The trigger dashboard

Service Requests → Workflow Triggers (role Workflows or RC Admin) shows how the triggers of all offers went.

Failures say why:

ReasonMeaning
the address answered 500It was reached but did not answer 200 (call mode) or 2xx (webhook). Look at the receiving system.
the address is not allowedNot http/https, has a user name, or is a private address while the instance does not allow those.
no answer within 10 secondsThe receiver is too slow. Let it answer first and work afterwards.
could not connectWrong host, port or certificate, or the system is down.
too many redirectsMore than three; use the final address.

Every run also leaves a short note in the request's history, and a failed call before finishing shows the reason on the page where the person clicked Done.

7. Webhook events and n8n

Besides the step trigger, the normal webhooks (Global settings → External services → Webhooks, or per team) carry the workflow:

EventWhen
workflow.starteda request was started (data: the master task)
workflow.step_readya step can be worked on: the first steps at the start, later ones when the step before is done
workflow.completedthe last step was finished and the master task closed
task.created, task.updated, task.donefor the master task and every step, like any task

Every task event of a workflow task carries the workflow block shown above, with the request fields and step fields in fields. Private tasks never leave the system.

An n8n flow

  1. In n8n add a Webhook node (method POST for the webhook mode, GET for call before finishing), copy its production URL and paste it as the step's trigger address. Add ?size=<size> if you want a value in the query.
  2. Add a Code node that verifies X-RC-Signature with the secret (snippet above; docs/webhooks/n8n-task-done.json shows the pattern for task.done).
  3. Do the work (create the account, order the device, open a ticket in another system).
  4. Optionally report back: put the result in the step's fields with PUT /tasks/{id}/workflow-fields and finish the step with PUT /tasks/{id} ({"done": 1}) - section 8. In webhook mode the step is already done, so use this for the next step, which a workflow.step_ready subscription tells you about.

8. REST API and MCP

CallWhat it doesMCP tool
GET /workflowsthe offers the caller may start, with request fields, steps and step fields (never a trigger address)list_workflows
GET /workflows/{id}one offerget_workflow
POST /workflows/{id}/startstart a requeststart_workflow
GET /tasks/{id}/workflowthe request, step and fields of a taskget_task_workflow
PUT /tasks/{id}/workflow-fieldsfill a step's fieldsset_task_workflow_fields
PUT /tasks/{id} with done: 1finish a step: checks the step fields, runs a call before finishing trigger, wakes the next steps, closes the request after the lastupdate_task
curl -u USER:TOKEN -X POST https://YOUR-INSTANCE/api/v1/workflows/4/start \
  -H 'Content-Type: application/json' \
  -d '{"title": "Laptop for Max", "solution_id": 3, "fields": {"size": "M"}}'
# 201 {"request_id": 13538, "step_ids": [13539, 13540, 13541], "url": "..."}

curl -u USER:TOKEN -X PUT https://YOUR-INSTANCE/api/v1/tasks/13540/workflow-fields \
  -H 'Content-Type: application/json' -d '{"fields": {"ticket": "INC-7"}}'

curl -u USER:TOKEN -X PUT https://YOUR-INSTANCE/api/v1/tasks/13540 \
  -H 'Content-Type: application/json' -d '{"done": 1}'

The token needs the read and write scope for everything but the two GET calls. Finishing a step is refused with 400 and the reason while a step field is empty or a call before finishing trigger fails.

Rules and limits