Pending-Proposal Tracker
A worked example of an advanced workflow: a Claude-managed scheduled agent that, once a week, surfaces outstanding sales proposals — documents sent for signature but not yet completed — grouped by how long they have been sitting in that stage, with their total outstanding value and a flag on those nearing or past expiry. It posts a digest to Slack as a canvas with a one-line summary. There are no servers and no code to deploy: the agent is a saved prompt plus a schedule plus two MCP connectors, running in Claude's cloud.
What it builds
The finished workflow runs unattended every Monday morning. Proposals quietly go stale and revenue slips when nobody is watching the "sent, awaiting signature" pile — a weekly nudge surfaces the ones that need a follow-up before they expire. Each run, the routine lists all open PandaDoc documents (status: sent or viewed), buckets them by age in stage (under 7 days, 7–14 days, over 14 days and going stale), sums the total outstanding proposal value, and separately flags any documents whose expiry date is within 7 days or already past. It publishes the digest as a Slack canvas and posts a one-line summary to your sales channel. The routine is entirely read-only on PandaDoc; the only write is delivering the report via the Slack connector.
Prerequisites
Before building, your Claude account needs all of the following:
| Requirement | Notes |
|---|---|
| WYRE MCP Gateway connector | Connected in claude.ai (https://mcp.wyre.ai/v1/mcp). Provides the gateway tools. See the Gateway overview. |
| PandaDoc connector in the gateway | The PandaDoc connector surfaces its tools through the gateway. Verify with gateway__search_tools (query: "pandadoc") and use the exact tool names the catalog returns — the names used in this guide (pandadoc_list_documents, pandadoc_get_document) follow the gateway's naming convention but should be confirmed before creating the routine. |
| Slack connector | The first-party Slack connector connected in claude.ai (https://mcp.slack.com/mcp). Provides slack_create_canvas and slack_send_message. |
| Scheduled routines access | Created via the /schedule capability; managed at claude.ai/code/routines. |
| A destination Slack channel | e.g. #sales, plus its channel ID. The Slack connector must have access to it. |
Known gotchas
These are the things that cost real time the first time through. Account for them up front and the build genuinely takes minutes.
- Confirm the PandaDoc tool names from the gateway catalog before building. The
tool names in this guide (
pandadoc_list_documents,pandadoc_get_document) follow the gateway's<vendor>_<action>_<entity>naming convention and are the most likely names — verify by callinggateway__search_toolswith query"pandadoc"and use whatever names the catalog actually returns. Setting wrong tool names inpermitted_toolsmeans the routine runs with no effective tools. - PandaDoc document status vocabulary is specific — read it from the API, do not assume.
PandaDoc documents move through states including
draft,sent,viewed,completed,declined, andexpired. The routine filters tosentandviewed(open, awaiting signature). The exact status strings the API accepts as filter values should be confirmed from the live connector — do not hardcode assumed values before verifying against the actual payload. - Filter to open statuses — do not sweep the full document history.
Without a status filter, PandaDoc may return every document ever created (completed,
declined, archived, draft). Sweeping the full history risks exceeding the routine's
payload capacity and hitting the 60-second tool timeout. Filter to
sentandviewedfrom the start. -
permitted_toolsmust be populated per connector. A routine with a connector attached but an emptypermitted_toolslist runs with no tools and silently does nothing — no error, no output. List the exact tool names the routine needs, using the confirmed names from the gateway catalog. - A routine reaches only its attached connectors. The routine sandbox blocks arbitrary network egress, so notifications must go through the Slack connector's tools, not an outbound webhook. Attach every connector the workflow touches.
- Faster-than-hourly cadences are rejected; cron is in UTC. This
routine uses
0 13 * * 1— Monday 09:00 America/New_York is 13:00 UTC (EST). During EDT (summer), America/New_York is UTC-4, so 09:00 EDT =0 13 * * 1still holds. Confirm your preferred UTC offset. - If Slack does not appear in the
/scheduleconnector list, read itsconnector_uuidandurlfrom an existing routine that already uses Slack (RemoteTrigger list → get → mcp_connections). - Prefer the list payload over per-document gets. The fields needed
for bucketing, value totalling, and expiry flagging (sent date, value, expiry, status)
should all be available in
pandadoc_list_documentswithout a per-record fetch. Callpandadoc_get_documentonly on specific flagged documents where the list payload is missing a needed field. Per-record calls across a full proposal list risk the 60-second tool timeout.
The one-shot build prompt
With the connectors above in place, paste this to Claude. It confirms the gateway
and PandaDoc reachability, creates the routine with both connectors and
populated permitted_tools, and verifies it end to end.
Build me a scheduled Pending-Proposal Tracker agent. Do all of this
end to end:
1. Confirm the WYRE MCP Gateway works and PandaDoc is reachable: call
gateway__search_tools with query "pandadoc" to confirm the tool names, then
call pandadoc_list_documents with a minimal filter (status: sent or viewed,
limit: 5) and check it returns document records without erroring. Note the
exact tool names the catalog returns — use those names everywhere below.
2. Confirm a Slack connector is connected. Note the destination channel name
and ID (e.g. #sales). If Slack does not show in the /schedule connector
list, read its connector_uuid and url from an existing routine that already
uses Slack (RemoteTrigger list -> get -> mcp_connections).
3. Create a Claude-managed scheduled routine named "Pending-Proposal Tracker":
- Schedule: weekly, cron "0 13 * * 1" (Monday 09:00 America/New_York =
13:00 UTC). Faster-than-hourly cadences are rejected.
- Attach TWO connectors, each with permitted_tools populated:
* WYRE MCP Gateway: pandadoc_list_documents, pandadoc_get_document
(use the exact names confirmed from the catalog above)
* Slack: slack_create_canvas, slack_send_message
An empty permitted_tools list = the routine runs with no tools.
- Routine prompt: every run, list documents in sent/viewed (open, not yet
completed or declined) status, bucket them by age in stage
(<7 days / 7-14 days / >14 days going stale), sum the outstanding
proposal value, flag documents nearing or past their expiry date, build
the digest, publish it as a Slack canvas titled "Outstanding Proposals —
<date>", and post a one-line summary to the channel. Use the exact
routine prompt below.
4. Trigger a manual run and verify: a canvas titled "Outstanding Proposals —
<date>" was created, a one-line summary landed in the destination channel,
and the proposal list and value totals look plausible against your
PandaDoc data (spot-check one sent proposal). The resulting routine prompt
This is the lean prompt the build process installs into the scheduled routine itself. Substitute your own destination channel ID.
You are the Pending-Proposal Tracker. You run weekly. Keep it lean.
Use ONLY: pandadoc_list_documents, pandadoc_get_document,
slack_create_canvas, slack_send_message.
(Confirm these tool names against the gateway catalog via gateway__search_tools
before the first run — use whatever names the catalog returns.)
Today's date in ISO format: <today-YYYY-MM-DD>
--- OUTSTANDING PROPOSALS ---
1. Call pandadoc_list_documents filtered to open statuses only:
status: sent, viewed
Do NOT include completed, declined, or draft documents — filtering to
open statuses prevents sweeping completed history and hitting the
60-second tool timeout.
If no documents are returned, post a one-line Slack message:
"Outstanding Proposals - <today>: no open proposals awaiting signature."
and stop.
2. For each document record, read: document name, recipient name(s),
total value/amount, the date it was sent (created or date_sent field),
and the expiry date (if present).
3. Bucket each document by age in stage — days since it was sent:
Bucket A: sent < 7 days ago (recently out, normal follow-up)
Bucket B: sent 7-14 days ago (follow-up warranted)
Bucket C: sent > 14 days ago (going stale — needs attention)
"Stale" threshold: any proposal with no signature after 14 days in the
sent/viewed stage.
4. Flag expiring and expired proposals:
- EXPIRING SOON: expiry date is within 7 days from today (or already
past). If the document has no expiry date set, do not flag it under
this heading — note "no expiry set" in the record instead.
- List expiring/expired proposals separately, regardless of their bucket.
5. Sum the outstanding proposal value:
- Total value across all open documents (Buckets A + B + C combined).
- Subtotal per bucket.
- If a document's value field is null or zero, include it in the count
but label its value as "value not set" rather than treating it as $0.
6. If detail on a flagged document is needed (e.g. to confirm expiry date
or recipient), call pandadoc_get_document for that specific record only.
Do not call pandadoc_get_document for every document in the list —
prefer the fields available in the list payload.
--- REPORT ---
7. Build the canvas body:
Heading: "Outstanding Proposals — <today>"
Sub-heading: "Total outstanding value: $<total> across <N> proposals"
SECTION A — Expiring / Expired
List each flagged proposal: name, recipient, value, expiry date,
days until expiry (or "expired <N> days ago").
Omit this section if no proposals are expiring within 7 days.
SECTION B — By Age in Stage
One sub-section per bucket (< 7 days / 7-14 days / > 14 days):
Proposal name | Recipient | Value | Sent date | Days in stage
End each sub-section with a subtotal (count and combined value).
Omit a bucket sub-section if it has no documents.
8. slack_create_canvas with that content, titled "Outstanding Proposals — <today>".
Then slack_send_message to the destination channel:
"Proposals <today>: <N> open (~$<total> outstanding), <X> expiring soon —
see canvas"
Include the canvas URL in the message if available.
9. If pandadoc_list_documents fails or returns an error, post a Slack
message: "Pending-Proposal Tracker could not read documents — check
gateway/PandaDoc connectivity." and stop. Do not retry in a loop. How it works
A weekly cadence, by design
Proposals do not need minute-by-minute monitoring — they need a weekly human nudge before they go cold. Running every Monday morning means the sales team starts each week with a clear view of what is still in flight and which proposals are overdue for a follow-up call. A weekly cron is also efficient: one PandaDoc list call per week rather than per day, with no meaningful loss of signal for a document-signing workflow that operates on a human timescale.
Age-in-stage bucketing and expiry flagging
Rather than dumping a flat list of all open proposals, the routine groups them by how long each has been sitting in the sent or viewed stage: under 7 days (recently sent, normal follow-up cycle), 7–14 days (follow-up warranted), and over 14 days (going stale — needs attention this week). This triage means the sales team can immediately see which proposals need a call today versus which can wait until later in the week. Separately, documents whose expiry date is within 7 days (or already past) are surfaced in their own section at the top of the canvas, regardless of their age bucket — an expired proposal that nobody noticed is a deal already lost.
Outstanding value as the headline number
The canvas header leads with the total outstanding proposal value across all open documents, mirroring the MRR-at-risk framing used in the Contract Renewal Tracker. That single number tells a sales leader whether to treat this week's open list as a minor housekeeping task or a priority revenue recovery. Each age bucket also carries its own subtotal so the distribution of value across urgency tiers is immediately visible. The routine is read-only on PandaDoc; the only write is posting to Slack.
Extending it
The natural first extension is pairing this tracker with the Contract Renewal Tracker for a full commercial picture: proposals in flight on one side, existing contracts approaching renewal on the other. Together they cover the two ends of the revenue calendar — new deals waiting to close and current deals at risk of lapsing.
A second extension is a handoff trigger: when a proposal moves to
completed status (signed), a downstream routine (or a manual
follow-up prompt) could create the corresponding onboarding ticket in Autotask or
HaloPSA, pre-populated with the client name, proposal value, and any products listed
in the document. The PandaDoc connector's document detail tool provides the
payload for that handoff.
Questions or a workflow you'd like documented?
Open an issue
in the msp-claude-plugins repository.