Turning an Unpaid Invoice into a Phone Call, Automatically
Automated collections outreach from Salesforce to Amazon Connect and back
The problem
Collections calls used to mean someone manually pulling a list of overdue accounts and dialing through it. That doesn't scale, and it leaves no consistent record of what was tried or what happened. The fix was to make the call itself part of the pipeline: Salesforce identifies who needs to be called, an automated voice flow makes the call and collects an outcome, and that outcome is written back onto the same record — without anyone dialing a number by hand.
The shape of the flow
The pipeline moves in one direction and closes the loop in a second pass. First, outstanding invoices are pulled out of Salesforce and queued up as call jobs. Each job becomes an outbound call placed through Amazon Connect, which plays the invoice details and gathers a response — payment confirmation, a request to speak to an agent, or no answer. Whatever the outcome, it's tracked through to completion and then reconciled back onto the Salesforce invoice as a status field, so the next person who looks at that account sees exactly what was attempted and how it went.
Overdue invoices pulled from Salesforce, queued as outbound call jobs.
Amazon Connect flow runs, collecting payment status, agent transfer, or no answer.
A periodic sweep of finished calls writes the final outcome back to the invoice.
Create vs. update, decided once
As with any system feeding an external channel from Salesforce, the direction of truth had to be unambiguous. Salesforce is the only place a call job originates — nothing on the calling side ever invents a new invoice or account. Every status the call flow produces is matched back to the invoice it came from and applied as an update. A call that can't be matched, or that ends in an ambiguous state, is left for the next reconciliation pass rather than guessed at.
What a flow like this actually needs
Call jobs move through several states before they're done. A queue keeps each one moving independently instead of one slow call blocking the batch behind it.
A call isn't a single request/response — it has a lifecycle. Something needs to track where each call is until it reaches a final outcome, separate from the system of record.
Every call has to trace back to the exact record that triggered it, so the outcome lands on the right invoice and never on the wrong one.
Writing outcomes one at a time doesn't hold up at volume. Batched writes, with partial-failure handling, keep a few bad records from blocking everything else.
Calls fail silently, get dropped, or end in a state nothing anticipated. A periodic sweep that re-checks and closes out anything unresolved is what makes the loop trustworthy.
Internal write-up — kept intentionally high-level. For implementation specifics, see the pipeline source directly.