DEV Community

Nitin Doyal
Nitin Doyal

Posted on

Inside the Booking-Deposit State Machine of a Free Calendly Alternative with UPI Payment

Deposits turn a booking into a state machine

A scheduling page with no money involved answers one question: is the slot free or taken? Add a deposit and that boolean stops being enough. The booking now lives in a small set of states, each with its own timeout, owner, and failure path — and the product either models them or rediscovers them as bug reports.

So read any free calendly alternative with upi payment as a state machine with a payment rail hanging off the side, not as a booking form with a payment field bolted on. The interesting questions are all about transitions: what triggers one, what happens when the same event arrives twice, and what happens when no event arrives at all.

These transitions come from SWIQ's own deposit flow. The narrative version is in SWIQ's free Calendly alternative with UPI payment guide; here we look at the machine itself.

SWIQ booking flow - book in three taps, real-time slot availability

The five states, and who owns each transition

SWIQ models a paid booking as five states, each with one incoming rule:

  1. slot_held — the slot is reserved on a server-side timer. Owned by the booking service; expires silently if nothing follows.
  2. deposit_link_sent — a UPI intent or link is issued against the hold, with an expiry always shorter than the hold itself.
  3. upi_reference_verified — amount, reference, and payee match. The countdown stops.
  4. confirmed — the UPI reference is written onto the booking row, the customer is messaged, and nobody else can take the slot.
  5. refunded / released — two distinct terminals. Refunded means money went back; released means the slot returned to inventory with no money taken.

The trap is treating these as tags: a tag can be overwritten silently, while a state machine refuses transitions that are not on the allowed list. That matters when money is involved.

What a Free Calendly Alternative with UPI Payment Must Get Right: Idempotent Callbacks

Payment rails repeat. A UPI callback can arrive twice, late, out of order, or after your server stopped waiting. SWIQ keys every callback to a unique merchant reference, and a duplicate is a no-op: if the booking is already upi_reference_verified, the replay only bumps last_seen_at.

The rule that prevents most double-booking incidents is never transition on arrival, transition on state. deposit_link_sent plus a verified payment becomes confirmed; confirmed plus the same payment stays confirmed. A handler that reads "payment succeeded" and writes confirmed unconditionally lets a replayed callback resurrect a booking the customer already cancelled.

Three defences cover most of it: a unique constraint on the payment reference, a guard that rejects confirmed → confirmed, and a processed-events table so a retry after a crash lands on the same path.

Reconcile against the UPI reference, not the timestamp

Timestamps lie in both directions — a callback can arrive before your hold is committed, or hours after someone intervened manually. SWIQ's reconciliation pass matches on UPI reference and amount first, then asks which state the booking is in. Never the reverse.

That gives you a clean nightly sweep: payments with no booking attached (customer paid a lapsed link → auto-refund or park for review) and bookings stuck in deposit_link_sent past expiry (→ released). Reconciliation becomes a report, not a panic job — and support gets one identifier both sides can quote.

No-show policy as a transition rule, not a paragraph in your bio

A no-show policy is usually prose on a booking page. As a state machine it becomes a scheduled rule: confirmed → no_show after a grace window, then no_show → refunded only if your deposit terms say so. Because the policy is code, the customer message and the money outcome cannot drift apart.

The other side matters too. A hold that expires is not a no-show — nobody ever paid — so it goes to released, not no_show, and no refund path opens. Keeping those terminals separate is what stops "why was I charged" landing in your inbox.

Edge cases you will meet in the first month

  • Payment lands after the hold expired. The slot was released and rebooked; the reference is real but the booking is gone → refund plus a priority rebook.
  • Wrong amount. Verification requires an exact match, so a short payment parks in verification_failed instead of half-confirming.
  • Customer pays twice. Two references, one booking → the second queues for refund automatically.
  • Callback for a cancelled booking. The guard rejects it; the payment goes to refund.
  • Staff confirm manually. Same states, different trigger — but if staff can write confirmed without a reference, reconciliation will never balance.

Each is boring on a diagram and expensive as an if-statement discovered during a refund.

Copy-ready: state transition checklist

Paste this into your PR description:

Booking-deposit transition checklist

  • slot_held expires on a server-side timer, never on page refresh
  • Deposit link expiry is strictly shorter than the slot hold
  • Every UPI callback is keyed by a unique merchant reference; duplicates are no-ops
  • Verification requires reference + amount + payee match, not just a "success" string
  • confirmed writes the UPI reference onto the booking row
  • Illegal jumps (confirmed → slot_held) are rejected
  • No-show, release, and refund are three separate terminal states
  • A nightly sweep matches payments to bookings by reference
  • Every transition emits booking_id, from_state, to_state, ref, at

Read the flow end to end in SWIQ's free Calendly alternative with UPI payment post — same machine, customer's side — while the appointment payment and booking system post covers how payment and booking share one record.

About SWIQ

SWIQ is a booking and queue system built in Jodhpur, India, for businesses taking appointments and walk-ins — and deposit-backed bookings are where the model above came from. Plans start at ₹777 per month, the first 300 bookings are free, setup takes 2 minutes with no card, and a 14-day free trial lets you test the transitions yourself. More at swiq.services and the product landing page, or WhatsApp +91 79002 60076.

SWIQ - your queue is calling. Set up in 2 minutes, first 300 bookings free

Top comments (0)