How to Route Large Wholesale Orders Through Multi-Tier Approval Before Fulfillment
Build a Spojit workflow where a new wholesale order arrives by webhook, a Condition checks its value, large orders pause for sign-off from both a sales manager and a finance approver, and only after both approve does NetSuite release the order and Slack notify the warehouse.
What This Integration Does
Wholesale and B2B orders are not like retail checkouts. A single large purchase order can tie up inventory, credit, and freight capacity, so most distributors want a human to sign off before the warehouse picks it. This workflow puts that control inside Spojit: when your storefront or order platform fires a webhook for a new wholesale order, Spojit inspects the order value, and any order above your threshold is held for approval by two different roles at once. A sales manager confirms the commercial terms and a finance approver confirms credit and payment, and the order only moves to fulfillment when both have approved. Small orders skip the hold entirely and pass straight through.
The workflow is triggered by an inbound HTTP POST to a Webhook trigger, so it runs the moment an order is placed. The order payload flows into a Condition that compares the total against your limit. Large orders enter a Human node configured with two approval slots, which pauses the run until every slot is satisfied. On approval, a Connector node calls NetSuite update-record to flip the order into a released or approved state, and a Slack send-message posts the order details to your warehouse channel. If an approver rejects or the request times out, the run halts and the order is never released, so re-running the workflow always starts from a clean, un-approved state.
Prerequisites
- A NetSuite connection in Spojit with permission to read and patch sales order records (see Connections → Add connection).
- A Slack connection with permission to post messages, and the channel ID or name of your warehouse channel.
- A signing connection for the Webhook trigger. If your storefront can sign requests, use a matching scheme (Spojit, Shopify, GitHub, Slack, or Custom HMAC); otherwise create a Custom signing connection.
- The NetSuite internal ID of each incoming order, or a field in the webhook payload that maps to it, plus the record type you use for sales orders.
- The Spojit users, roles, or teams who should approve. You need at least one sales manager identity and one finance identity, since each goes in a separate approval slot.
- A value threshold that defines a "large" order (for example, orders over 10,000 in your order currency).
Step 1: Receive the order with a Webhook trigger
Add a Trigger node and set its type to Webhook. Spojit gives the workflow a unique URL and verifies each call against your chosen signing connection. Point your storefront or order management system at this URL so it POSTs a JSON body whenever a wholesale order is created. The trigger returns 202 with an executionId and exposes the parsed JSON body to later steps. A typical body looks like:
{
"orderId": "SO-48217",
"netsuiteRecordId": "10472",
"customer": "Northwind Trading Co",
"currency": "AUD",
"total": 18450.00,
"lineCount": 27
}
Reference these fields downstream with handlebars, for example {{ trigger.total }} and {{ trigger.netsuiteRecordId }}. If your platform cannot sign requests, use a Custom signing connection so Spojit can still verify the call is genuine.
Step 2: Route by order value with a Condition node
Add a Condition node directly after the trigger. Create a rule that compares the order total against your threshold, for example {{ trigger.total }} is greater than 10000. The Condition gives you a True branch and a False branch. Connect the True branch to the approval step you build next, so only large orders are held. Connect the False branch straight to the NetSuite release step (Step 4), so small orders skip approval and release immediately. This keeps the slow human path reserved for the orders that actually warrant it.
Step 3: Require dual sign-off with a Human node
On the True branch, add a Human node. This is where the multi-tier control lives. Set a clear Label such as Large wholesale order approval and a Message that summarizes the order, for example:
Order {{ trigger.orderId }} for {{ trigger.customer }} totals
{{ trigger.total }} {{ trigger.currency }} across {{ trigger.lineCount }} lines.
Approve to release for fulfillment.
The key field is Approval slots. Create two slots:
- Slot 1 - Sales manager: add an atom for your sales manager User, or a Role or Team that represents sales managers. Any atom in the slot satisfies that slot.
- Slot 2 - Finance: add an atom for your finance approver User, Role, or Team.
Because Spojit uses AND semantics across slots, the run continues only when every slot is satisfied. One person approving is not enough: a sales manager and a finance approver must each act before the order is released. Set a Timeout (minutes) if you want stale requests to expire (a timeout is treated as a reject and halts the run), choose an Urgency of High for large orders, and optionally enable Email approvers so the first ten named approvers are emailed. Approvers act in the Approvals inbox at /approvals, on the dashboard widget, or via the menu badge. On approval the node outputs { approved: true, approvalId, outcome: "APPROVED" } and the workflow continues.
Step 4: Release the order in NetSuite with a Connector node
Add a Connector node on the NetSuite connector in Direct mode and pick the update-record tool. Direct mode is deterministic and costs no AI credits, which is what you want for a single, predictable patch. Map the inputs:
recordType: the record type you use for sales orders (for examplesalesOrder).id: the order's internal ID, for example{{ trigger.netsuiteRecordId }}.body: a JSON object with the fields that mark the order as released or approved in your account.
A patch body might look like:
{
"orderStatus": "_pendingFulfillment",
"memo": "Released by Spojit after dual approval {{ trigger.orderId }}"
}
Use the exact field names and status values your NetSuite account expects, since these vary by configuration. Both the True branch (after approval) and the False branch (small orders) should converge on this release step so every order that proceeds is released the same way.
Step 5: Notify the warehouse with a Slack message
Add another Connector node on the Slack connector in Direct mode and choose the send-message tool. Set the channel to your warehouse channel and build the message text from the order and approval data, for example:
Order {{ trigger.orderId }} for {{ trigger.customer }} is approved and
released. Total {{ trigger.total }} {{ trigger.currency }}, {{ trigger.lineCount }}
lines. Approval ID {{ approval.approvalId }}. Please begin picking.
Because this node only runs after NetSuite has been updated, the warehouse is told to pick only orders that are genuinely released. You can place the Slack step on both converging branches so small orders also generate a pick notification, or only on the post-approval path if you notify small orders elsewhere.
Step 6: Optional - confirm to the sales team with Send Email
If you want the salesperson who entered the order to get a written confirmation, add a Send Email node after the Slack step. It sends from Spojit's built-in mail service with no connection required. Set Recipients to the sales owner's address, a templated Subject like Order {{ trigger.orderId }} approved and released, and a short Body summarizing the outcome. Remember that external recipients must be on your org allowlist under Settings → General → Email recipients, and these messages count toward your monthly email allowance. To send from your own domain instead, use the Resend or SMTP connector.
Tips
- Keep approval slots aligned to Roles or Teams rather than single users where possible, so a holiday or absence does not block every large order. Roles cascade, so an Owner can satisfy a slot that lists Admin or Member.
- Use a meaningful Notification title/body on the Human node with
{{ }}variables so approvers see the customer name and total without opening the run. - Put the order total and currency in the approval message so finance can judge credit risk at a glance, and tier your threshold per currency if you sell in more than one.
- If you want different thresholds for different customers, add a second Condition branch or use Miraxa, the intelligent layer across your automation, to scaffold the extra branching: try "Add a Condition node that checks if
{{ trigger.total }}is over 50000 and route the true branch to a third approval slot."
Common Pitfalls
- Expecting an "on reject" branch. A rejected or timed-out approval halts the run; downstream branching on rejection is not supported. Design for "approve to proceed," and handle rejected orders manually in NetSuite.
- Putting both approvers in one slot. If both the sales manager and finance atoms sit in a single slot, any one of them satisfies it and you lose the dual sign-off. Use two separate slots to get AND semantics.
- Wrong NetSuite field or status value. The
update-recordbodymust use the exact field names and status codes your account expects, or the patch is rejected. Confirm them in a sandbox before going live. - Webhook replays. If your platform retries deliveries, enable opt-in dedup via the event-id header on the Webhook trigger so a single order does not create two approval requests.
- Slack channel mismatch. Make sure the Slack connection has access to the warehouse channel; posting to a private channel the connection has not joined will fail.
Testing
Test on a small, safe scope first. Send a test POST to the Webhook URL with a low total that falls under your threshold and confirm the order skips the Human node, releases in a NetSuite sandbox, and posts to a test Slack channel. Then send a payload with a total above the threshold and confirm the run pauses at the Human node and an approval appears in the Approvals inbox. Approve as only the sales manager first and verify the run stays paused, then approve as finance and confirm the run continues, releases the order, and posts the Slack message. Use the execution history to inspect each step's output, including the Human node's approved and approvalId values, before pointing production order traffic at the workflow.