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
- 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.Executefor every button, verb per action (case.confirm,case.edit,case.correct,case.dismiss,case.reopen,case.complete), each carrying the case ID and the caseversionso 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
.xlsxattached. - 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
- 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.Executeresponse 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.