Skip to main content
DoneThat

AI Adoption GuideHospitalityReturn

Loyalty milestone trigger agent

Monitors CRM for points-expiry, anniversary, and birthday events, then fires a personalized retention offer automatically.

Hospitality processBookConfirmPrepareArriveStayDepartReviewReturn

By Don, DoneThat’s AI coach · updated

The output is a cited draft, not a send

A loyalty milestone trigger agent should produce one thing: a draft retention offer that names the CRM event it is responding to. The event is points expiry, a stay or membership anniversary, or a birthday. If none of those sit on the guest file, the offer field stays empty. A loyalty manager still decides whether anything goes out.

The agent does not auto-send. Treating a generated paragraph as already delivered is a failure mode, not a shortcut. The CRM, the property system, and the email or app channel stay under a person who can see the guest, the offer, and the cite.

The cite is not decoration. An offer with no event on the page is unusable. A manager cannot tell whether the system reacted to a real birthday, a real anniversary, or nothing. Quality means the draft is checkable: event type, CRM date or window, and offer language a person can approve or kill.

Do not invent a points balance. If the CRM records that points expire on a date, cite that date. If the file does not carry a balance, leave the balance out. Making up a number to sound personal is worse than a thin draft, because the guest can see the real balance in the app or on the next statement.

Hospitality CRMs such as Revinate, Oracle Hospitality, and Mews store these events in different objects and field names. Treat them as a class of systems that already hold membership dates, birth dates, and points-expiry flags. The agent reads those fields. It does not become the system of record.

Load points-expiry, anniversary, and birthday from the CRM

Start by loading events, not by writing copy. For each guest in the return window, pull points expiry, anniversary, and birthday. Pull only what the file actually contains. A missing birthday is a missing birthday. Do not backfill from a booking comment or a guess.

Anniversary can mean membership start, last stay, or another date your program already uses. Use the field your loyalty team already trusts. Mixing member-since with last-visit in the same batch produces drafts that cite the wrong milestone. Confirm which anniversary the property uses before you run the agent.

Load the expiry date the CRM exposes. Load a balance only if that field is present and your team is allowed to put it in guest-facing copy. Many files have an expiry flag and no safe balance. In that case the draft may say that points are due to expire on the CRM date, and stop.

Birthday is a calendar event. Load month and day, and year only if you already store it and need it for age-gated offers you already run. Do not invent a birthday to fill a campaign calendar.

If you already retrieve broader loyalty context for other return work, keep this load narrow. loyalty context retrieval assembles history and program facts. This agent is for the three trigger events. Do not dump the full stay history into the offer. The manager needs the event, not a biography.

A return propensity scorer can tell you who is worth a human look this week. It does not replace the event load. A high-propensity guest with no milestone on file still gets an empty offer from this agent.

Write the offer so the event is visible on the page

Once events are loaded, draft only for guests who have at least one. The draft should make the cite obvious to a person scanning a queue: which event, which date or window from the CRM, which offer the property already allows for that event.

Use language your program already approved. If birthdays get a food-and-beverage credit and points expiry gets a stay-extend or a bonus-earn window, those are the offers. The agent is not inventing a promotion. It is attaching an existing offer to a cited event.

One illustrative pass: a guest file shows a birthday on 12 March and a points-expiry date of 31 March. The CRM has no points balance field the team is allowed to quote. The draft names the birthday, names the expiry date, and attaches the birthday amenity and the expiry reminder the program already uses. It does not print a made-up point total. A second guest in the same batch has a last stay last year and no birthday, no anniversary field, and no expiry flag. That guest's offer field stays empty.

Put the cite where the manager will see it without opening a second screen. A header line such as CRM event: birthday 12 March; points expiry 31 March above the guest-facing paragraph is enough. If the only thing in the body is warm copy, the draft failed the quality bar even if the tone is fine.

Do not merge this draft with a broader re-engagement letter unless a person asks for that merge. A hyper-personalized re-engagement generator is a different job. The milestone trigger stays short and event-tied so the manager can approve it in the loyalty queue. If the stay is already over, use the personalized farewell message generator. Do not recycle a birthday or expiry offer into a farewell.

Empty stays empty when the file has no event

No event on the file means no draft. Empty is a valid result. Filling the blank with a generic we-miss-you line is an offer with no event cite.

Empty also applies when the event is stale by your own rules. If points already expired last month and the CRM still shows a historical flag, leave the offer empty unless that flag is still an active trigger. Do not write a late note that cites an event the guest already lived through.

Empty applies when the field is present but unusable: a birthday of 1 January that your team treats as a placeholder, an anniversary that is the hotel's opening date copied onto every member, a points-expiry of a sentinel date. Those are data-quality issues. The agent should not turn them into a send.

The manager's queue should show empty rows. Hiding them makes coverage look complete. Empty rows are the guests this agent must not invent a reason to contact.

The loyalty manager still sends

Override auto-fire. The draft sits in a review list. A person reads the cite, checks the offer against current inventory and current program rules, and sends or discards.

Do not treat the draft as sent. If someone assumes the mail system already dropped the campaign, you get silence, double sends, or both. The send lives in the channel you already use: email, app inbox, or a desk note. The agent does not own that channel.

Check the cite against the CRM at send time, not only at draft time. A birthday that was next week when the batch ran may have passed. Points that were due to expire may have been redeemed. If the event is gone, do not send the old draft. Delete it or regenerate after a fresh load. Do not patch in a new points balance from memory.

The person who sends is accountable for tone, eligibility, and whether this guest should get a commercial message. The agent cannot see a bereavement note, a complaint in another queue, or a duplicate membership. When the manager sends, they send the approved text. If they change the offer, they still keep the event visible so later review can see why the guest was contacted.

Is this worth automating for you?

Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other.

DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.

Measure the baseline first