Daily
Catch paid orders that haven't shipped
Each day you see paid orders that are still unfulfilled after 2 days.
- Runs
- Daily
- Apps
- Shopify
- AI
- Not needed
- Access
- read_orders
Send this to your assistant
Create a ClickRuntime automation: every day at 10am, Slack me Shopify orders that are paid but still unfulfilled more than 48 hours after they were placed.
First time? Adding ClickRuntime to your assistant takes about two minutes.
Why use it
Why teams use this automation
A customer paid on Monday and by Thursday has heard nothing. In the store's backlog, their order sits among forty others, each one apparently fine because Shopify shows it as paid. Perhaps stock was miscounted, the pick list missed it, or the person who handles it was out sick. Nobody notices until the customer writes an annoyed email, opens a dispute, or leaves a one-star review that mentions slow shipping.
Each day, ClickRuntime asks Shopify for orders that are paid, still unfulfilled and created more than two days ago, then posts the list to your team's Slack channel with order number, age, customer and total. Orders disappear from the list as soon as they are fulfilled, so the post is a short list of what truly needs attention.
Small teams that ship from a single desk and larger ones with a fulfillment partner can both use it as a safety net.
What you get out of it
Late shipments are caught on day three
A short daily list means a delayed order is noticed while the customer is still waiting patiently, not after they have escalated. A fast apology and ship date often saves the relationship.
Hidden problems get exposed
Orders usually stay unfulfilled for a reason: out of stock, a wrong address, a held payment. Seeing them repeatedly forces someone to find the cause rather than letting them age in the queue.
Chargebacks become less likely
Customers who never receive an order frequently dispute the charge. Shipping or refunding within a few days of payment removes the most common reason for disputes about non-delivery, and the fees that come with them.
Review scores are protected
Slow shipping is a frequent complaint in public reviews. A routine check on aging orders prevents the long tail of waits that turn into complaints on Google, Trustpilot or your product pages.
Handovers need no briefing
When a colleague covers for someone on leave, the daily post tells them exactly which orders are overdue. There is no need to explain a spreadsheet or the informal system the previous person kept.
How it works
What happens, step by step
Every day, the automation looks for Shopify orders that are paid but still not fulfilled.
It keeps the ones placed more than two days ago.
The list is posted to your Slack channel with each order number, customer, total and the date it was placed.
Before it runs live
- Connect Shopify
What you get
Build your own
Need it to work differently?
Your own rules
Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.
Any number of apps
One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.
AI where it helps
Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.
On a schedule or on each event
Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.
Changes you can ask for
- Run it at a different time, more or less often, or only on weekdays
- Add an AI step, for example to summarize, sort or draft a reply
- Add another app, for example also send it to Slack
- Combine it with other Shopify steps into one automation
Under the hood
The code that runs this automation
from datetime import datetime, timedelta, timezone
from clickruntime import on_trigger, credentials, http, notify
STORE = "your-store.myshopify.com"
def gql(query, variables=None):
resp = http.post(f"https://{STORE}/admin/api/2025-07/graphql.json",
headers={"X-Shopify-Access-Token": credentials.connection("shopify", "store")},
json={"query": query, "variables": variables or {}})
resp.raise_for_status()
return resp.json()["data"]
@on_trigger
def run(event):
cutoff = (datetime.now(timezone.utc) - timedelta(hours=48)).strftime("%Y-%m-%dT%H:%M:%SZ")
orders = gql("""query($q: String!) { orders(first: 100, query: $q) { nodes { name createdAt
customer { displayName } totalPriceSet { shopMoney { amount } } } } }""",
{"q": f"financial_status:paid fulfillment_status:unfulfilled created_at:<{cutoff}"})["orders"]["nodes"]
if not orders:
return {"late": 0}
lines = [f"• {o['name']} · {(o['customer'] or {}).get('displayName', 'guest')} · "
f"{float(o['totalPriceSet']['shopMoney']['amount']):,.2f} · placed {o['createdAt'][:10]}" for o in orders]
notify.slack(f"{len(orders)} paid orders unfulfilled after 48h:\n" + "\n".join(lines), channel="#store")
return {"late": len(orders)}FAQ
Common questions
Does it include orders waiting on payment?
Can I change the two-day threshold?
What about partially fulfilled orders?
What permissions does it need?
Does it need AI?
How many runs does it use?
Can I change how it works?
Related
You might also like
Get last week's orders as a CSV
Every Monday you get all of last week's orders in one file, with customer, total and status.
See how it worksGet a daily list of abandoned checkouts
Each evening you get today's abandoned checkouts with the customer email, cart value and recovery link, so you can follow up.
See how it worksGet warned when stock runs low
Each morning you see the variants running low, and each one is only flagged once.
See how it worksKeep exploring
Set up “Catch paid orders that haven't shipped” from your assistant
Copy the prompt above, or connect your assistant first. Free plan, no credit card.