Request icon
OutputValues icon
Sequential icon
Log icon
SlackIncomingWebhook icon
Pause icon

Purchase Order Finance Approval Gate

Reusable Kestra subflow that enriches a purchase order with product details, notifies Slack, pauses for manager approval, and returns the decision as outputs.

Categories
Business

Make finance sign-off a reusable building block instead of an email thread. This Kestra blueprint is a self-contained approval stage: it receives a product id, requestor, and department, enriches the request with live product details, notifies the finance channel in Slack with a link to an approval form, pauses until a manager decides, and returns managerApproved and managerComments as typed flow outputs. Any parent flow, like the companion product-order-approval-hitl blueprint, can call it with io.kestra.plugin.core.flow.Subflow and branch on the verdict. The approval link uses appLink(), which resolves when a Kestra App (an Enterprise Edition and Kestra Cloud feature) is bound to the flow.

How it works

  1. The flow accepts three inputs, productId, requestor, and department, so callers pass context, not payloads.
  2. The getProductDetails task (io.kestra.plugin.core.http.Request) fetches the product record from the catalog API (dummyjson.com as a stand-in) using the trimmed productId.
  3. The appParams task (io.kestra.plugin.core.output.OutputValues) extracts productName, productPrice, and productImageLink from the JSON body. These values are base64-encoded into the App link so the approval form can render a rich card with name, price, and image instead of a bare execution id.
  4. Inside the hitlProcess block (io.kestra.plugin.core.flow.Sequential), sendApprovalNotification logs the approval URL and notifyChannel (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) posts it to the finance channel, both embedding the flow inputs and display parameters via {{ appLink() }}&flowInputs=...&appParams=....
  5. The waitForApproval task (io.kestra.plugin.core.flow.Pause) suspends the execution with an onResume schema of a BOOLEAN decision and a STRING reason. The execution holds durably until the manager submits the form or resumes from the UI.
  6. Flow-level outputs map the resume answers to managerApproved (BOOL) and managerComments (STRING), giving parent flows a clean, typed contract.

What you get

  • A drop-in finance approval stage callable from any flow via Subflow.
  • Rich approval context, product name, price, and image, delivered to the approver's form.
  • Durable pausing: the request waits indefinitely without consuming a worker.
  • A typed output contract so callers branch on the decision with simple expressions.

Who it's for

  • Finance and procurement teams formalizing purchase order sign-off.
  • Platform engineers composing multi-stage approval chains from reusable subflows.
  • Teams replacing approval-by-email with auditable, structured decisions.

Why orchestrate this with Kestra

Approval logic embedded in every business flow gets duplicated, drifts, and becomes impossible to audit consistently. Extracting the gate into a subflow gives you one implementation with one notification format, one decision schema, and one place to change policy. Kestra's Pause holds state server-side for as long as the decision takes, the parent-child execution link preserves lineage from request to verdict, and the onResume inputs turn a human decision into structured data the rest of the pipeline consumes like any other output.

Prerequisites

  • Outbound HTTP access to your product or catalog API (dummyjson.com works for testing).
  • A Slack incoming webhook for the finance channel.
  • A Kestra App bound to this flow so appLink() resolves (EE or Kestra Cloud); without one, replace the link with the execution URL.
  • Optionally the product-order-approval-hitl blueprint as an example caller.

Secrets

  • SLACK_WEBHOOK: Slack incoming webhook URL used by notifyChannel.

Quick start

  1. Add the SLACK_WEBHOOK secret to your Kestra namespace.
  2. Deploy the flow and execute it manually with a test productId such as 1.
  3. Follow the Slack message (or open the paused execution), answer the approval questions, and resume.
  4. Check the managerApproved and managerComments outputs on the execution.
  5. Call it from a parent flow with io.kestra.plugin.core.flow.Subflow and branch on the outputs.

How to extend

  • Add an amount threshold input and auto-approve orders under a limit with runIf.
  • Escalate stale approvals by setting a timeout on the Pause and notifying a second approver.
  • Record decisions in a database with io.kestra.plugin.jdbc.postgresql.Query for reporting.
  • Swap Slack for Teams or email notifications from the notifications plugin family.
  • Chain a payment or ERP task after approval, gated on managerApproved.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.