Human-in-the-loop for travel and expense agents
Most trips are in policy. The exceptions are what need a person.
Let the agent book what fits policy on its own, and route the exception to whoever owns the budget.
How do I let an AI travel agent auto approve inside policy and ask a human for exceptions?
Pushary gives an AI travel or expense agent one call that reaches a real person and waits for their answer. Book inside policy automatically, then wrap the out-of-policy fare, the upgrade, or the over-limit claim in decisions.ask() so the agent holds until the budget owner approves, denies, or types a cheaper instruction. If nobody answers before your window closes it fails closed, so an unattended booking never becomes a charge nobody authorised.
Where it stops
The calls that should not be automatic
- bookFlight(itinerary, fareClass)
- A fare above the policy ceiling is the classic exception, and it is time-boxed: the price is only good for a few minutes. That is exactly the case where an approval sitting in an inbox costs real money, because the fare is gone before anyone reads the email.
- upgradeCabin(bookingRef, cabin)
- Cabin rules usually depend on facts the agent does not hold: flight length, who is travelling, whether a client is paying. A person can settle that in one tap, and the rule is often unwritten anyway.
- approveExpense(reportId, amount)
- Reimbursing an over-limit claim is money leaving the company with no clean undo, and it is the line item an auditor asks about later. The record of who approved it matters as much as the decision.
- rebookDisruption(bookingRef, newItinerary)
- A cancelled flight at 6am is where an agent is most useful and least supervised. Rebooking into a higher fare to get someone home is usually right, but it should still be somebody's call rather than a default.
- issueTravelAdvance(employeeId, amount)
- Advances move cash before any receipt exists, so the usual after-the-fact expense controls do not apply. The approval is the only control there is.
The integration
Two calls inside the step you already have
Wrap the action, not the whole agent. Everything the agent does that is safe keeps running without asking anyone.
import { createPusharyServer } from "@pushary/server"
const px = createPusharyServer({ apiKey: process.env.PUSHARY_API_KEY! })
async function book(trip: TripRequest, fare: Fare) {
// In policy and under the ceiling: the agent just books it.
if (fare.total <= POLICY.ceilingFor(trip.route) && fare.cabin === "economy") {
return bookFlight(trip.itinerary, fare.cabin)
}
const decision = await px.decisions.ask({
externalId: trip.budgetOwnerId,
type: "confirm",
question: `Approve ${fare.currency}${fare.total} for ${trip.traveller}? Policy ceiling is ${POLICY.ceilingFor(trip.route)}.`,
timeoutMs: 9 * 60 * 1000,
})
if (!decision.approved) return holdForCheaperFare(trip)
return bookFlight(trip.itinerary, fare.cabin)
}Who answers
The approver is usually not an engineer
The person whose budget the trip lands on, which is usually a line manager or a cost centre owner rather than anyone in travel operations. That is the point: travel teams administer the policy, they do not own the money, so routing every exception to a shared travel inbox puts the decision with people who cannot actually say yes. Pushary sends it to the budget owner's phone and comes back with a decision attached to their name.
We already have an approval step in our booking tool. Why add another one?
Most booking tools do have an approval step, and it is usually an email with a link into a portal the approver has not logged into for a month. That is fine for a trip planned three weeks out and useless for a fare that expires in nine minutes or a disruption at six in the morning. The gap is not that approval is missing, it is that the approval arrives on a channel nobody is watching at the moment the decision matters. Pushary does not replace your travel policy or your booking tool. It moves the exception onto the phone the approver already has in their hand, gives it a deadline, fails closed when the deadline passes, and writes who decided what into a record you can export. If your current step already gets answered inside the fare window, you do not need this.
Worth reading: IRS Publication 463 on travel expense substantiation, GSA per diem rates, the ceiling most US travel policies inherit.
Embed it in your product. Your users never see a Pushary login or bill.
FAQ
Questions, answered
Can an AI travel agent auto approve inside policy and only ask about exceptions?
What happens if the approver does not answer before the fare expires?
Who should approve an out-of-policy trip, travel operations or the manager?
Does this work for expense reports as well as bookings?
Put a person on the step that needs one.
Connect a user with one tap, ask a human with one call, and act on a fail-closed decision. Every decision is saved to a durable ledger you can audit.