🔒 PROTOTYPE DEMO · Payments · The Microsoft Teams cards the JY Payment Bot posts. Design authority for developers. Payment review →
Payments · Design reference
Teams cards · reference
Payment review

Every card the JY Payment Bot posts to the Teams chat Payments review (Andy Yu, Leo Chan). Build them as Adaptive Cards exactly as shown. Each card has a spec beside it: what triggers it, who sees it, what every button does, what is stored, and what the card becomes afterwards. The cards marked Live demo respond to clicks; the rest are static.

Rules common to every card
These apply before anything in the per-card specs
The portal is the recordA card is a view drawn from the payment case. Deleting a card loses nothing; the portal can post it again.
Saved before the card updatesEvery click is written to the portal (case + a payment_case_events row + an audit row) first. Only then is the card redrawn. If the save fails, the card does not change and the clicker sees the error.
First click winsIf Andy and Leo press at the same moment, the first saved action stands. The second person gets the redrawn card showing who acted and when, not a second write.
Only Payments · Review may actChecked in the route, from the clicker's Entra ID mapped to a portal user. Anyone else gets card K, shown only to them.
Reopen before completionA confirmed, corrected or dismissed case can be reopened until it is completed. Completed cases are closed; changes after that are made in the portal.
The bot never posts in client groupsWhatsApp and Telegram groups are read only. Every card, reminder and question goes to the internal Teams chat.
APayment review cardAwaiting reviewLive demo
PC-0031 · try Correct, Edit and Not an order
Trigger
A payment proof (screenshot, PDF, bank receipt, USDT screenshot) arrives in a linked group, or is dropped in the Teams chat. The AI reads it, matches it to an open Xero invoice of the group's linked client(s), and runs the six checks. One card per payment case. The bot never confirms on its own.
Who sees it
Everyone in Payments review. Only holders of Payments · Review can press the buttons.
Buttons
  • Correct — the AI's values are stored as confirmed. Status → Payment confirmed. Nothing is written to Xero; the bookkeeper records the payment there as today.
  • Edit — expands inline inputs, shown only to the person who pressed it: client (only the group's linked clients), invoice(s) (multi-select from the Xero copy, open invoices only, no free text), amount received, date, note. Save correction → Payment confirmed · corrected. Saving with nothing changed is stored as a plain confirmation.
  • Not an order — one tap reason: Not a payment → dismissed; Duplicate → pick the original, linked and closed; Wrong client → re-queued under the chosen client (a new card is posted); Other → dismissed with a required note.
  • Reopen (after any of these) → back to Awaiting review. Mark complete (after confirming) → Completed, the fallback when no "done" message is seen.
Stored
The case fields, the proof file (virus-scanned), the messages relied on, the AI's original reading with confidences (kept after a correction), the six check results, each action with who, when, reason and per-field before → after.
Afterwards
The card is redrawn for everyone with the new status, who acted and when, and loses the review buttons. A correction shows the before → after table. It counts as an AI correction in the weekly report. No action for 4 working hours → reminder (card G).
Build notes
Action.Execute for every button, verb per action (case.confirm, case.edit, case.correct, case.dismiss, case.reopen, case.complete), each carrying the case ID and the case version so a stale click is refused. Edit uses a per-user refresh (refresh.userIds), so the form appears only for the clicker.
BPayer warning variantAwaiting reviewLive demo
PC-0030 · payer is a person, not the company
Trigger
Same as card A, when check 2 fails: the payer on the proof is not the group's company and is not a known payer for any linked client. Directors often pay personally, so this is a warning, not a block.
Who sees it
Everyone in Payments review; only Payments · Review can act.
Buttons
As card A, plus a toggle Remember LIM WEI JIE as a payer for Client Y (CFD), on by default. It is read when Correct or Save correction is pressed.
Stored
As card A. With the toggle on, the payer name is added to the client's known payers, with who added it and from which case. Next time check 2 passes for that name.
Afterwards
Confirmed card with the line "LIM WEI JIE saved as a known payer for Client Y (CFD)". Known payers are listed and removable on the client's record.
CFinal states: confirmed, corrected, dismissedStatic
PC-0026 · PC-0027 · PC-0028
Trigger
A reviewer's action on card A or B. The same card is updated in place; no new message is posted.
Confirmed
Green status with reviewer and time. Buttons: Reopen, Mark complete.
Corrected
Green "Confirmed · corrected" status, the before → after table (AI value struck through, reviewer's value beside it) and the note. Same buttons as confirmed.
Dismissed
Grey status with the reason. A duplicate names and links the original case. Button: Reopen. Dismissed cases are left out of totals and counted on their own line in the weekly report.
Stored
Nothing new beyond the action that produced the state. The card is redrawn from the case each time.
D"New group" cardLive demo
KX Treasury 付款群 · WhatsApp
Trigger
The bot's WhatsApp number or Telegram bot is added to a group it does not know. Until someone links it, the bot stores nothing from that group.
Who sees it
Everyone in Payments review; only Payments · Review can act.
Buttons
  • Link to Client K — the suggestion, from the group name and members' phone numbers matched to CRM contacts.
  • Choose another — a single client select from the CRM, then Link.
  • Link several — tick two or more clients (one owner, several entities), then Link.
  • Ignore — the group is never read. Can be undone on Chat groups.
Stored
The group (channel, name, member count, date added) and its link(s) or its ignored flag, with who decided and when. No messages from before the link.
Afterwards
Card shows "Linked to … by … at …" or "Ignored", with a link to Chat groups where it can be relinked, unlinked or un-ignored.
E"Which order is done?"Live demo
N Group entities · two open cases
Trigger
A registered JY staff member (here Mei Wong) posts a "done" message (done / 完成 / completed) in a group with more than one open case, and neither an invoice number nor an amount in the message decides which. The bot asks; it never guesses.
Who sees it
Everyone in Payments review; only Payments · Review can answer.
Buttons
One button per open case in that group (case, client, invoice, amount), and Neither.
Stored
The chosen case is completed, with the staff message stored as its completion message and the reviewer who chose it. Neither: the message is kept on the group but linked to no case.
Afterwards
"Completed PC-… (chosen by …)" or "Not linked to any case". The completed case's own card changes to card F.
Note
The shared sample data has no group with two open cases, so the second case here (PC-0032, Client B, USD 900.00) is illustrative.
FCompleted cardStatic
PC-0029 · Client M Holdings
Trigger
A staff "done" message is matched to one case (for example "✅ 已完成 INV-2026-0141"), a reviewer answers card E, or a reviewer presses Mark complete.
Who sees it
Everyone in Payments review.
Buttons
Open in portal (the case page) and History (the case's event list). No Reopen: completion closes the case in Teams.
Stored
Completion time, the completion message (sender, group, text, message ID) or the reviewer who marked it complete.
Afterwards
Final. The case's review card is replaced by this one.
GReminder cardStatic
Tue 10 Jun · 13:00
Trigger
A case has waited 4 working hours (Mon–Fri 09:00–18:00 MYT) for review. One reminder lists every case waiting at that moment, oldest first; each case is reminded about once. The interval is still to be agreed with the client.
Who sees it
Everyone in Payments review, with Andy Yu and Leo Chan @mentioned.
Buttons
Show per case — scrolls the chat to that case's card. Open Payment review — the portal list filtered to Awaiting review.
Stored
A "reminded" event on each listed case.
Afterwards
Stays as posted. Cases still waiting on Saturday appear under "Awaiting review" in the weekly report.
HFlag: confirmed but unpaid in XeroStatic
PC-0026 · Client Q
Trigger
A daily check at 09:00 MYT finds a case confirmed more than 3 days ago whose Xero invoice is still not PAID in the portal's Xero copy. Posted once per case.
Who sees it
Everyone in Payments review.
Buttons
Open in Xero — links out to the invoice in Xero (the portal never records payments there). Open case — the portal case. Check Xero now — runs the sync for that invoice and replies with the result.
Stored
A "flagged: unpaid in Xero" event on the case.
Afterwards
When the Xero copy shows the invoice PAID, the card is redrawn as resolved ("Recorded in Xero on …"). Still-flagged cases are listed under exceptions in the weekly report.
IChannel alertAlertLive demo
Trigger
The WhatsApp listener sends a heartbeat each minute. Disconnected: no heartbeat for 10 minutes. Logged out or banned: posted at once. The same card is used for the Telegram bot (webhook failing) and for Xero (connection expired). The failure mode is silence, so this must be loud.
Who sees it
Everyone in Payments review, with Andy Yu and Leo Chan @mentioned.
Buttons
Open Integrations — the portal page with the re-link QR. I'm on it — records who is handling it, so the other reviewer does not duplicate the work.
Stored
The outage (start, end, type) on the channel, and who acknowledged it.
Afterwards
When heartbeats resume the card is redrawn green: "Reconnected at …, down for … min". It also says to check the groups by hand for proofs posted during the gap.
JWeekly report cardStatic
Sat 13 Jun · 07:00 MYT · figures as they stand on Tue 10 Jun
Trigger
Every Saturday at 07:00 Malaysia time (0 7 * * 6, tz: Asia/Kuala_Lumpur). Window: the previous Saturday 00:00 to Friday 23:59 MYT.
Who sees it
Everyone in Payments review. The same content is emailed to Andy Yu and Leo Chan as an HTML email with the .xlsx attached.
Content
New, confirmed, completed and dismissed counts; totals by currency and by company (confirmed only; dismissed excluded); open cases by age; exceptions (short, payer mismatch, duplicate, already paid in Xero, confirmed but unpaid in Xero); cases awaiting review; AI corrections made by reviewers.
Buttons
Open in portal — Payment review filtered to that week. Download .xlsx — the same spreadsheet as the email attachment.
Stored
The report run (window, figures, file) so a past week can be downloaded again.
KRefusal replyLive demo
Jason Tan (no Payments · Review) presses Correct
Trigger
Any card button pressed by someone without Payments · Review, or by a Teams user not linked to a portal account. Checked in the route, not by hiding buttons.
Who sees it
Only the person who clicked (the Action.Execute response to that user). Everyone else keeps seeing the unchanged card.
Text
"Only payment reviewers can act on this card." For an unlinked Teams account: "Your Teams account is not linked to a portal user. Ask an Owner to link it."
Stored
Nothing on the case. A refused-action row in the audit log (who, which card, which button).
Afterwards
The case is unchanged and still awaiting review.