shopify-admin-order-hold-and-release
Purpose
Places or releases holds on fulfillment orders programmatically without navigating the Shopify admin. Useful for fraud review queues, inventory shortages, or payment verification workflows. Works on orders with fulfillment orders in OPEN status.
Prerequisites
shopify auth login --store <domain>- API scopes:
read_orders,write_merchant_managed_fulfillment_orders
Parameters
Universal (store, format, dry_run) + skill-specific:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| action | string | yes | — | hold or release |
| order_ids | array | no* | — | Array of order GIDs to target (e.g., ["gid://shopify/Order/123"]) |
| query_filter | string | no* | — | Shopify order search query to select orders (e.g., "tag:fraud-review") |
| reason | string | no | OTHER |
Hold reason: AWAITING_PAYMENT, HIGH_RISK_OF_FRAUD, INCORRECT_ADDRESS, INVENTORY_OUT_OF_STOCK, OTHER |
| reason_notes | string | no | — | Free-text note visible to fulfillment staff |
| hold_until | string | no | — | ISO 8601 date when hold auto-expires (optional) |
*One of order_ids or query_filter is required.
Safety
⚠️ Step 2 places or releases holds on live fulfillment orders. Holding an order prevents it from being fulfilled and may delay delivery. Releasing a hold allows fulfillment to proceed immediately. Run with
dry_run: trueto preview which orders will be affected before committing.
Workflow Steps
-
OPERATION:
orders— query Inputs:order_idslist orquery_filterstring; fetch each order'sfulfillmentOrdersto get the fulfillment order IDs and currentstatusExpected output: List of fulfillment order GIDs with their currentstatus; skip any already in the target state (already held / not held) -
OPERATION:
fulfillmentOrderHold— mutation (ifaction: hold) Inputs:id: <fulfillmentOrderId>,fulfillmentHold: { reason, reasonNotes, holdUntilDate }per fulfillment order Expected output: UpdatedfulfillmentOrder.status: ON_HOLD,userErrorsOR
-
OPERATION:
fulfillmentOrderReleaseHold— mutation (ifaction: release) Inputs:id: <fulfillmentOrderId>per held fulfillment order Expected output: UpdatedfulfillmentOrder.status: OPEN,userErrors
GraphQL Operations
# orders:query — validated against api_version 2025-01
query OrdersForHold($first: Int!, $after: String, $query: String) {
orders(first: $first, after: $after, query: $query) {
edges {
node {
id
name
displayFulfillmentStatus
fulfillmentOrders(first: 5) {
edges {
node {
id
status
requestStatus
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
# fulfillmentOrderHold:mutation — validated against api_version 2025-01
mutation FulfillmentOrderHold($id: ID!, $fulfillmentHold: FulfillmentOrderHoldInput!) {
fulfillmentOrderHold(id: $id, fulfillmentHold: $fulfillmentHold) {
fulfillmentOrder {
id
status
}
remainingFulfillmentOrder {
id
status
}
userErrors {
field
message
}
}
}
# fulfillmentOrderReleaseHold:mutation — validated against api_version 2025-01
mutation FulfillmentOrderReleaseHold($id: ID!) {
fulfillmentOrderReleaseHold(id: $id) {
fulfillmentOrder {
id
status
}
userErrors {
field
message
}
}
}
Session Tracking
Claude MUST emit the following output at each stage. This is mandatory.
On start, emit:
╔══════════════════════════════════════════════╗
║ SKILL: order-hold-and-release ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
After each step, emit:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>
If dry_run: true, prefix every mutation step with [DRY RUN] and do not execute it.
On completion, emit:
For format: human (default):
══════════════════════════════════════════════
OUTCOME SUMMARY
Orders targeted: <n>
Fulfillment orders held/released: <n>
Skipped (already in target state): <n>
Errors: 0
Output: none
══════════════════════════════════════════════
For format: json, emit:
{
"skill": "order-hold-and-release",
"store": "<domain>",
"started_at": "<ISO8601>",
"completed_at": "<ISO8601>",
"dry_run": false,
"steps": [
{ "step": 1, "operation": "OrdersForHold", "type": "query", "params_summary": "<filter or ids>", "result_summary": "<n> fulfillment orders found", "skipped": false },
{ "step": 2, "operation": "FulfillmentOrderHold|FulfillmentOrderReleaseHold", "type": "mutation", "params_summary": "<n> fulfillment orders, action: <hold|release>", "result_summary": "<n> updated", "skipped": false }
],
"outcome": {
"action": "<hold|release>",
"orders_targeted": "<n>",
"fulfillment_orders_affected": "<n>",
"skipped": "<n>",
"errors": 0,
"output_file": null
}
}
Output Format
No CSV. Inline summary table:
| Order | Fulfillment Order ID | Previous Status | New Status |
|---|---|---|---|
| #1001 | gid://...FulfillmentOrder/456 | OPEN | ON_HOLD |
Error Handling
| Error | Cause | Recovery |
|---|---|---|
fulfillmentOrder.status is already ON_HOLD |
Order already held | Skipped automatically — logged in output |
fulfillmentOrder.status is not OPEN or ON_HOLD |
Order is already fulfilled, cancelled, or in progress | Cannot hold/release; skip and report |
INVENTORY_OUT_OF_STOCK reason without note |
Some stores require a note for this reason | Add reason_notes parameter |
userErrors from mutation |
Insufficient scopes or invalid fulfillment order state | Verify write_merchant_managed_fulfillment_orders scope |
Best Practices
- Use
query_filter: "tag:fraud-review"to hold all orders tagged by your fraud detection process in one command. - Set
hold_untilto automatically release holds after a review window — prevents holds being forgotten on customer orders. - Always run
dry_run: truefirst when usingquery_filter— confirm the order count before holding dozens of orders at once. - Combine with
fulfillment-status-digestto identify held orders and then batch-release them after resolving exceptions. - The
AWAITING_PAYMENTreason is visible to fulfillment staff and provides context for why an order is paused.
More from 40rty-ai/shopify-admin-skills
shopify-admin-skills
Master skill collection for Shopify store operators. Provides access to all merchandising, marketing, support, and operations capabilities.
146shopify-store-skills
A brief description of what this skill does
16shopify-admin-variant-option-normalizer
Detects inconsistent variant option naming (Sm vs Small vs S) and bulk-corrects to a standard set.
5shopify-admin-discount-hygiene-cleanup
Finds expired, zero-usage, or duplicate discount codes and optionally deactivates or deletes them.
5shopify-admin-gift-card-issuance
Issue Shopify gift cards (store credit) to customers as a goodwill gesture, post-return incentive, or loyalty reward.
5shopify-admin-fulfillment-status-digest
Generate a daily fulfillment triage digest: all open orders segmented by fulfillment age and flagged for holds or exceptions.
5