Your Dunning System Retried the Card. Did a Human Ever Call?
The customer had been paying $1,900 a month for two years. In March the card on file expired. Stripe's smart retries did what they were configured to do: attempted the charge again after two days, again after four, again after seven. Each attempt fired the standard payment-failed email from the billing system. On day fourteen the subscription moved to canceled and the account went read-only.
The account manager found out from the customer, who wrote to her directly asking why the dashboard had locked. She checked Stripe. Four failed attempts, four automated emails, one cancellation. She checked her own sent folder. Nothing. She checked the shared inbox. Nothing. She checked Slack. There was one message in the #billing channel from a teammate on day three that said "heads up, Northwind's card is bouncing, anyone talking to them?" and nobody had replied.
That is the whole story. The system worked. The retries ran on schedule. The emails sent. The invoice records are perfect. And a two-year customer churned because for fourteen days, not one person picked up a phone.
The Question Recovery Tooling Does Not Ask
Dunning tools are built around a specific question: did the retry sequence execute correctly? They answer it well. You can see attempt counts, retry intervals, email open rates, recovery rate by card type, revenue recovered this month versus last. If your question is "is our dunning configured properly", the tooling is genuinely good.
The question that actually matters when a large account fails is different. It is: for each failed payment above some threshold, did any human being make contact, and if so who, and when relative to the first failure?
That question has no home. It is not a Stripe question, because Stripe knows about charges and invoices and has no idea whether your account manager sent an email from Gmail. It is not a Gmail question, because your inbox does not know which threads are about a failed payment. It is not a CRM question, because logged calls in HubSpot sit in a different system from the failure event that should have prompted them. The answer exists, but it exists split across three tools, and the join key is a customer identity that each tool spells differently.
So nobody asks. Not because the question is hard to care about, but because assembling the answer means someone spending an afternoon with three browser tabs and a spreadsheet, and that afternoon never gets scheduled.
Why Your BI Stack Cannot See It
Be precise about this, because the tempting version of the argument is wrong.
Modern BI tools are more capable than the pitch decks of two years ago suggested. Power BI Copilot answers questions in natural language. Looker's Conversational Analytics does the same against a semantic model. Tableau Pulse will surface anomalies without being asked. If your question is expressible over modelled tabular data, these tools will handle it, and handle it better than a hand-rolled console.
The problem is upstream of the question. It is what these tools can see at all.
Looker connects over SQL dialects. That is the connection model: a warehouse, a database, something that speaks SQL. Metabase ships nineteen official drivers, and every single one of them is a database. If your Stripe data is synced into Snowflake, wonderful, the failure events are queryable. But the evidence for "did anyone call" is a sentence someone typed in a Slack thread, a paragraph in a sent email, a note field on a HubSpot activity. There is no driver for a Slack message. There is no semantic model over a sent folder. The evidence is not in a shape any of these tools connects to, so the question never gets raised in a BI context, and over time people stop believing it is a reporting question at all.
There is a second structural problem. The question is retrospective. It asks what already happened and who dropped it. Trigger-based automation platforms like Zapier and Make are built around "when this event occurs, do that". They are good at the forward-looking version: when a payment fails, create a task. Looking backwards at the last ninety days is a different shape of problem. Their run history is a log of what the automation did while it was switched on, not a record of what people did afterward in Slack and email.
What The Join Actually Requires
Write it out plainly and it stops feeling mysterious.
| Piece | Where it lives | What it contributes |
|---|---|---|
| Failed charge events, last 90 days | Stripe | Customer, amount, first failure date, attempt count, current subscription status |
| Customer to account mapping | HubSpot or Salesforce | Which internal owner is responsible, contact email addresses |
| Sent email threads | Gmail or Outlook | Whether an outbound message went to a contact on that account after the first failure |
| Logged calls and meetings | HubSpot activity timeline | Whether a person recorded a conversation in the window |
| Internal chatter | Slack | Whether anyone raised it, and whether anyone answered |
Four sources, five if you count Slack separately. The hard part is not any single lookup. It is that the answer requires matching a Stripe customer to a CRM company to an email domain to a Slack thread, and then reasoning about a sentence: does "spoke to Dana, she's getting the new card from finance" count as contact? A human reads that and says yes instantly. A row-oriented query has nothing to grab.
Asking For It In A Sentence
Skopx connects to nearly 1,000 SaaS tools and to databases directly, which means Stripe, Gmail, HubSpot and Slack are all readable from the same place. You describe the console you want in chat, in ordinary language:
"Show me every Stripe payment failure in the last 90 days over $500 where the subscription is now past due or canceled. For each one, tell me whether anyone at our company emailed a contact on that account after the failure date, whether a call was logged in HubSpot, and whether it was mentioned in Slack. Sort by amount at risk, highest first. Give me a button on each row to email the account owner with the details."
It runs the query against what you already connected, looks at what actually comes back, and builds the page around the real result. If forty accounts come back, you get a table with filters. If three come back, you get three cards, because a table of three rows is a worse way to read three things. The measurement step matters more than it sounds: a console designed for the data that exists reads differently from one designed for the data someone imagined.
The Slack and email parts are where the language layer does work no query can. It is reading message bodies and judging whether a given thread constitutes contact about this account's payment problem. That is a reading task, and it is the reason this console is possible at all.
What The Console Shows
Four metrics along the top: total amount at risk, count of failures with zero recorded human contact, median days from first failure to first contact where contact happened, and count still unresolved past thirty days.
Then the table, one row per failed payment, sorted by amount. Customer, amount, first failure date, retry attempts, current status, account owner, and three contact columns showing what was found: an email on day six, a call logged on day two, nothing at all. The empty ones are the point of the page.
A bar chart underneath breaking response down by account owner, because the pattern is rarely uniform. Usually one or two people are on it every time and the gap sits with accounts that changed hands or never had a clear owner.
And on each row, a button. Clicking it opens a confirmation showing exactly what is about to happen and to whom: an email to the account owner containing the customer name, amount, failure date and the fact that no contact was found. You read it, you confirm, one action runs against one connected tool. Nothing fires on its own, nothing runs on a schedule, nothing acts because a condition was met. A person clicks, a person confirms.
The trace of that click lives where the action landed. The email sits in the sender's mailbox and in the recipient's, which is where the next person asking this question will look anyway. The console itself holds nothing: it reads your tools when you open it, and it acts on your tools when you press the button.
The Honest Version Of The Comparison
Retool can do a lot of this. You can query Stripe from a Retool app, put a button on a row, and have that button send an email or write back to a connected service. That is real, it works, and pretending otherwise would be dishonest. Retool AppGen will even scaffold an app from a prompt.
The difference is narrower than the marketing instinct wants it to be, and it is worth stating precisely. Building this in Retool means someone deciding to build it: writing the Stripe query, wiring the CRM resource, figuring out how to search a mailbox, and then writing the logic that decides whether a Slack thread counts as contact, which is the part that does not reduce to a query at all. That is a project. It gets scoped, prioritized, and usually deferred, because it is a reporting question and reporting questions lose to product work.
This console was authored from a sentence typed by the person who wanted the answer, in the afternoon they wanted it. That is the whole difference. Not capability, availability. The questions that never get built are not the impossible ones, they are the ones not worth a ticket.
Limits Worth Stating
An internal app reads and acts. It stores nothing. There is no record of "we reviewed this one" persisted in Skopx, because there is no write path except the button, and the button acts on your connected tools. If you want the review state to live somewhere, it lives in your CRM, put there by an action someone clicked.
The console does not run on a schedule and does not alert you. There is no form to fill in and nothing to capture. You open it when you want to look. If you want something recurring, that is a different mechanism and it lives in workflows, not here.
The contact detection is a judgment call made by reading text, and judgment calls are wrong sometimes. A call discussed verbally and never logged looks identical to a call that never happened. Treat a "no contact found" row as a prompt to check, not as proof of neglect.
Queries are read-only. Charts are bar, line, pie and area. If the answer needs a shape outside those, it is a table.
The Close
Nobody set out to let Northwind churn. The retry ran, the emails sent, the invoice history is clean, and every system involved performed exactly as configured. The failure sits in the gap between systems, in the space where a Slack message went unanswered and no report existed that would have shown it.
Team is $16 per seat per month with 2.3 million AI tokens included per seat, Solo is $5. Whether or not you build this particular console, it is worth knowing the answer to the question. For the last ninety days of failed payments over some amount you care about, how many got a person? If you cannot answer that today, the honest read is that some of them did not.
Skopx Team
The Skopx engineering and product team