Tattoo Booking Bot
Freelance platform: FastAPI, PostgreSQL, Stripe, and Meta WhatsApp with production-style webhook discipline
- Production (freelance)
- 2025 - 2026
- 43 commits last push Feb 2026
- FastAPI PostgreSQL SQLAlchemy Alembic Stripe WhatsApp Business Cloud API Google Sheets Google Calendar Docker pytest GitHub Actions
This is not a toy chatbot, it is a small integration-heavy backend. Money, third-party APIs, and asynchronous events land in the same service; the engineering work is state, retries, and tests.
Problem
Consultations arrived as unstructured WhatsApp traffic. The studio needed qualification, deposits, and scheduling without double charges, lost threads, or ambiguous handoff to artists.
User flow
- 13-question consultation flow with per-step validation (budget, location parsing, intent).
- Stripe Checkout for deposits; webhooks confirm payment before state advances.
- Google Calendar slot suggestions; Google Sheets for lead logging.
- Admin and artist approval workflow before hard commitments.
Architecture
FastAPI fronts Meta webhooks; PostgreSQL holds authoritative state. Outbound calls to Stripe, Google APIs, and WhatsApp are sequenced with explicit failure handling, no “best effort” on money movement.
Alembic tracks schema evolution; Docker packages the runtime; GitHub Actions runs automated checks.
Reliability and safety
- Webhook idempotency keys / dedupe strategies to survive retries and out-of-order delivery.
- Explicit handling for partial failures (API down, webhook late, user abandons mid-flow).
- Admin paths to inspect and correct state when automation is wrong.
- pytest coverage on parsers, state transitions, and payment edge cases.
Integrations
Each vendor is a contract: timeouts, structured errors, and logging that identifies which side failed. Stripe webhooks are reconciled against Checkout session state; Google APIs are treated as flaky dependencies.
What I learned
Conversational products are state machines, model the transitions, test illegal transitions, log decisions.
If Stripe is involved, idempotency and reconciliation are core features, not polish.