Skip to content

Return and resubmit

An approver who needs a change can return the request instead of rejecting it. The requester then resubmits, with a changed payload if needed, or withdraws it.

const returned = await rungs.return({
requestId: request.id,
actorId: "u_fin",
to: "requester", // or { stepId: "manager" } to send it back one step
comment: "Please attach the invoice",
});
console.log(returned.status); // "returned"
const resubmitted = await rungs.resubmit({
requestId: request.id,
actorId: "u_req",
payload: { amount: 320 },
});
console.log(resubmitted.status); // "pending", at the manager step again

Runs in CI:examples/docs-snippets/src/concepts/return.ts

The flow decides what runs again after a resubmit:

await rungs.flows.register({
key: "expense",
returnPolicy: "restart", // after a resubmit every step runs again; or "from-returned-step"
resubmitDeadline: "P7D", // optional: how long a returned request waits for the requester
steps: [
{ id: "manager", approvers: { type: "users", ids: ["u_mgr"] } },
{ id: "finance", approvers: { type: "users", ids: ["u_fin"] } },
],
});

Runs in CI:examples/docs-snippets/src/concepts/return.ts

  • "restart" (default): every step from the beginning; earlier approvals no longer count.
  • "from-returned-step": continue at the step that returned it. If the payload changed, Rungs restarts anyway, because earlier approvers approved different data (EC-34, EC-51).

An approver can also return to an earlier step instead of the requester (EC-33). A returned request accepts only resubmit, withdraw and an admin override.

By default a returned request waits as long as it takes. With resubmitDeadline, Rungs reminds the requester or, with onResubmitTimeout: "auto-withdraw", withdraws it (EC-52).