Chase overdue Xero invoices with Adyen payment links
A morning worklist of every unpaid Xero invoice, sorted by how late it is, with one click to send a card payment link and see who has paid.
Build me an app my finance team opens each morning to chase unpaid invoices and get paid by card. Xero is the invoice source, Adyen pay by link is the payment rail, and the app itself is the record of every link we have sent. This is a working surface for collectors, not a report: the operator decides which invoices to chase, sends the link, and works the queue down.
Main view: the outstanding invoice worklist
The landing view is a worklist of outstanding sales invoices loaded with Xero List Invoices, filtered to authorised invoices that still have an amount due, sorted by days overdue with the latest first. Columns: invoice number, customer name, invoice total with its currency, amount still due, due date, days overdue, current link status, who created that link, and the date it was last chased. Support filtering by collector, by minimum amount, and by a days-overdue threshold, plus a Mine toggle that narrows the list to links the current user created.
Two Xero data notes to handle: money fields come back as decimals such as 99.95 rather than cents, and dates arrive in .NET format like /Date(1551830400000+0000)/, so parse the millisecond timestamp before computing days overdue. Xero list responses are wrapped in a plural collection key and are paginated, so page through until every outstanding invoice is loaded.
Detail pane
Selecting a row opens a detail pane. Call Xero Get Invoice for the full record including line items, and Xero Get Contact for the customer behind it. Show a line items table with description, quantity, unit amount, tax and line total, a customer block with email, phone and billing address, and the full history for that invoice: every payment link created against it with its status and creator, and every chase note.
Create Payment Link
Every row has a Create Payment Link button, repeated in the detail pane. It calls Adyen Create Payment Link with the amount taken from the invoice, the merchant account from settings, an expiry date from the configurable default of 14 days, and the customer email from the Xero contact as the shopper email when one exists.
Two things must be exactly right here. First, the amount. Adyen takes amount as an object shaped { currency, value } where value is in MINOR units, so 1000 means EUR 10.00, while Xero gives you a decimal. Convert by multiplying by 100 for normal two decimal currencies, passing the whole number for zero decimal currencies such as JPY, and using thousandths for three decimal currencies such as BHD. Round to an integer carefully so floating point never shifts a cent. Use the invoice currency, never a hardcoded one. Second, always set reference to the Xero invoice number, because that is the string finance reconciles against when the money lands.
Create the link for the amount still due rather than the original total, so partly paid invoices request the right remainder.
App storage is the system of record
This is the constraint the whole app design hangs on. Adyen has no operation that lists or searches payment links, and no operation that lists payments. Adyen Get Payment Link only works when you already hold the link id. So the app must persist every link it creates and must never contain a view that assumes it can page through links or transactions held at Adyen.
On every successful creation, save to app storage: the Adyen payment link id, the hosted payment URL, the Xero invoice id, the Xero invoice number, the customer name, the amount value and currency, the current status, the expiry date, the creation timestamp, and the app user who created it. Keep the full history per invoice rather than overwriting, so a reissued link sits alongside the one it replaced.
Refresh Status
A Refresh Status handler loops over the stored link ids, calls Adyen Get Payment Link for each, and writes the result back to storage with a last-checked timestamp. Map the Adyen status values onto the three the app shows: active stays active, completed and paid both become Paid, expired becomes Expired. Handle an id that no longer resolves without failing the whole sweep, and show progress since this loops one call per stored link. Offer it as a button and run it automatically when the app opens if the stored statuses are stale.
Expired without payment
Give expired-and-unpaid links their own highlighted section at the top of the worklist, styled as needing attention, because these are invoices where someone did the work and the window closed. Each carries a Reissue button that creates a fresh Adyen payment link for the amount still due today and stores it against the invoice alongside the old one. When reissuing an invoice that still has an active link, call Adyen Update Payment Link Status first to expire the superseded link so the customer cannot pay through a stale URL.
Collector actions
Copy link puts the hosted payment URL on the clipboard in one click, with a visible confirmation, since collectors paste these into their own emails and calls. Mark as chased records the current user, the timestamp, and a free-text note against the invoice in app storage, then surfaces the most recent chase date and note in the worklist so nobody chases the same customer twice in a day. The detail pane shows the whole chase history.
Push a summary to Slack
A button posts a summary of outstanding links to a finance channel using Slack Bot Send a Message, with the channel chosen from a picker populated by Slack Bot List Channels and remembered in settings. Group the message by status: the outstanding total, the value sitting on live links awaiting payment, expired links needing reissue, and what has been collected this month. For each listed invoice include invoice number, customer, amount, days overdue, and who created the link.
Totals across the top
Three headline figures sit above the worklist: total outstanding value across the unpaid invoices in view, value that currently has a live link against it, and value collected this month from links that reached paid within the current calendar month. Group these by currency rather than adding different currencies into one meaningless number. Each total is clickable and filters the worklist beneath it.
Per-user attribution
Every link and every chase note is stamped with the person who did it, and the creator is a visible column in the worklist, not just stored metadata. A manager should be able to filter to one collector and see what they have sent, what came back paid, and what expired unworked.
Settings
A settings view holds the Adyen merchant account name, which Adyen requires in the body of each request and does not come from the stored credential, along with the default link expiry in days, the Slack channel for summaries, and the Xero organisation to read invoices from.
What does this prompt do?
- Opens to a worklist of every outstanding invoice from Xero, sorted by days overdue, so your team always knows who to chase first.
- Creates a card payment link for any invoice in one click, using the invoice total and the invoice number, so payments reconcile cleanly against your books.
- Keeps every link it creates in one place with a live status of active, paid, or expired, and highlights the ones that ran out before anyone paid so they can be reissued.
- Shows running totals for what is outstanding, what has a live link waiting, and what has been collected this month, and posts a summary to your finance channel in Slack.
What do I need to use this?
- A Xero account containing the sales invoices you want to chase
- An Adyen account set up to accept card payments, plus the name of the merchant account you bill under
- A Slack workspace and the finance channel you want summaries posted to, if you want that step
- A few minutes to decide how long payment links should stay valid before they expire
How can I customize it?
- Change how long a payment link stays valid before it expires, from a few days to a few weeks
- Filter the worklist by collector, by minimum amount, or by how many days past due an invoice is
- Choose which Slack channel receives the outstanding summary and how much detail it carries
FAQs
Does this change anything in my Xero account?
Why does the app keep its own record of payment links?
Can customers pay in the currency they were invoiced in?
Can I see who on my team sent which link?
What happens when a link expires before the customer pays?
Related templates
See how your brand's news coverage and sentiment stack up against four competitors, then let an assistant write the weekly report for you.
One screen showing every social post waiting on approval, sorted by deadline, so reviewers can approve or reject without leaving the page.
Every Monday, find the past champions and closed-won contacts who changed jobs, update Attio, and get the moves worth chasing in Slack.
Staff submit what happened, your social manager edits the copy, picks the accounts and puts it on the calendar without a single spreadsheet.
Open one board each morning, see which voice calls went badly, replay the exact moment the caller got frustrated, and file the fix.
A personal queue of every overdue Guru card, sorted by how late it is, with one-click verify, reassign, comment, and an agent that drafts the refresh for you.
Stop chasing invoices from a spreadsheet.
Give your finance team one screen that shows what is owed, sends the payment link, and tracks who paid.