Nikolai Pavlov's Work | ContraWork by Nikolai Pavlov
Nikolai Pavlov

Nikolai Pavlov

Senior Low-Code Architect | Supabase, WeWeb & FlutterFlow

New to Contra

Nikolai is building their profile!

Cover image for Taming the QuickBooks API: Architecting
Taming the QuickBooks API: Architecting a Bulletproof Financial Sync Grab a cup of coffee. Let’s talk about one of the most notoriously unforgiving tasks in software architecture: integrating a custom SaaS platform with enterprise accounting software like QuickBooks Online (QBO). If you’ve ever integrated Stripe or PayPal, you know it’s relatively straightforward. Money moves, a webhook fires, the status changes. But accounting software is different. It’s not just about moving money; it’s about Audit Trails, Chart of Accounts, and Tax Compliance. One wrong API call, and you can ruin a company's annual tax return. Recently, I led the architecture and integration of QuickBooks Online for Sound Equine Pro — a specialized CRM and financial management app for equine professionals (farriers, veterinarians). Here are the critical architectural challenges I faced and the solutions that turned a potential data nightmare into a seamless, invisible assistant for our users. Challenge 1: The "Source of Truth" Trap (Why Two-Way Sync is a Bad Idea) When clients ask for a QuickBooks integration, they usually say: "I want everything to sync both ways instantly." As an architect, my first job was to push back against this. If a bookkeeper changes an invoice amount inside QuickBooks to balance the books, should that change propagate back to the mobile app and overwrite the original invoice the farrier created in the barn? Absolutely not. The Architectural Rule: We established a strict boundary of responsibility. Sound Equine Pro is the Source of Truth for Operations (Clients, Horses, Services, Invoice generation). QuickBooks is the System of Record for Taxes. Data flows strictly One-Way (App ➔ QBO) for all master data and invoices. The only exception is Payments. If a client pays an invoice via a QuickBooks payment link, QBO sends a webhook to our app to close the balance. This separation prevents data mutation loops and protects the operational integrity of the app. Challenge 2: Domain Mapping (How do you put a Horse in QuickBooks?) QuickBooks doesn't have a "Horse" category. It has Customers, Vendors, and Items. But for a veterinarian, tracking profitability per horse is a killer feature. The Solution: Instead of flat mapping, we utilized QuickBooks' Sub-customer (Jobs) architecture. The human owner becomes the Customer. The horse becomes the Sub-customer (e.g., Larissa Maslow : Gunner's Hotrod). To make this work asynchronously, I designed a specialized SQL View (qbo_unified_horses_view) in PostgreSQL. This view intelligently combined both native application horses and "shadow" (offline) horses, retrieved their parent’s qbo_id, and fed a clean, flat data structure to our Edge Functions. The result? Flawless P&L reports for the CPA without the user doing any extra manual data entry. Challenge 3: Surviving the "Webhook Storm" and Race Conditions Modern apps use database triggers to keep data consistent. In our Supabase architecture, creating an invoice involves multiple steps: inserting the invoice, inserting items, calculating totals via triggers, and adding notes. Initially, this caused a massive Webhook Storm. Saving one invoice in the app fired 4-5 simultaneous UPDATE webhooks to our Edge Function. The Resulting Bug: Five parallel Serverless Functions raced to QuickBooks, trying to create the same invoice. QBO allowed it, creating duplicates. When we tried to update the invoice later, QBO threw a Stale Object Error (SyncToken collision). The Engineering Fix (Idempotency & Debouncing): I re-architected the qbo-sync-worker Edge Function into a robust Dispatcher. Locking Mechanism: The first webhook to arrive instantly writes a processing status to the database. The subsequent webhooks see this lock and gracefully terminate. Smart Filtering: The function compares old_record and new_record payloads from the Supabase webhook. If only technical fields changed, it aborts. Retry Logic with Backoff: If QuickBooks still throws a Stale Object Error due to rapid user edits, the function catches the error, waits for 2 seconds, fetches the latest SyncToken from QBO, and retries the operation. Challenge 4: The "Uncategorized" Grace To create an Item or Expense in QBO via API, you must provide an Income/Expense Account ID. But asking a farrier to map Chart of Accounts in a mobile app is terrible UX. The Automation: During the initial OAuth 2.0 handshake, a background worker silently queries the user's QuickBooks account for default accounts like "Uncategorized Expense". It saves these IDs to our database. When the user logs a $50 expense for horseshoes in the app, the worker routes it to the Uncategorized bucket. The CPA can easily review and reassign these at the end of the month. The Tech Stack Backend & Database: Supabase, PostgreSQL (with heavy use of Views and Row Level Security). Compute: Deno-based Edge Functions (Serverless). Integration: QuickBooks Online API (OAuth 2.0, Batch API for performance, Webhooks). *** Integrating with enterprise accounting software requires moving beyond basic CRUD operations. It demands defensive programming, strict data governance, and an understanding of how accountants actually work. By leveraging Event-Driven architecture and intelligent Edge Functions, we built a silent, powerful bridge that handles the financial heavy lifting, allowing equine professionals to do what they do best: care for the horses. Are you looking to integrate complex third-party APIs (ERPs, Accounting, Payment Gateways) into your SaaS without compromising performance or data integrity? Let's connect and discuss your architecture.
1
10
Cover image for Handling Chaos with Atomic Precision:
Handling Chaos with Atomic Precision: The Saldovia Inventory Engine Most booking systems are built on sand. They treat inventory as a simple number in a spreadsheet—a "count" that can easily go out of sync, leading to the nightmare of every operator: overbooking and lost revenue. When I architected the Saldovia Engine, I moved away from "counting" and toward Atomic Inventory. I don't just book a seat; I secure a specific physical slot in a specific window of time. This isn't just an app—it’s a resilient business infrastructure designed to eliminate human error at the database core. My architectural philosophy for this project was "Smart Backend, Thin Client." While most developers overload the user interface with logic, I buried the heavy lifting deep within the core of PostgreSQL (Supabase). Every critical business rule—from price calculations and availability checks to complex seat-locking mechanisms—is handled by custom-built PL/pgSQL functions and triggers. This ensures that the system is unhackable and consistent, regardless of what happens in the user’s browser. Whether the frontend is a web dashboard or a mobile app, the data remains absolute and synchronized. To manage the high-pressure environment of real-time bookings, I implemented a sophisticated Seat Lifecycle. Every resource in the system passes through four distinct states: Available, Held, Confirmed, or Blocked. To prevent race conditions—where two people try to buy the same seat at the exact same millisecond—I used Database-level Locking. If a user clicks a seat, the engine secures it for exactly 15 minutes. This creates a "safe zone" for the transaction to complete without friction or technical debt. But a great system must also clean up after itself. I built "The Janitor"—an automated Cron Job that wakes up every minute to scan the system for expired holds. If a payment wasn't completed, the Janitor instantly releases the resource back to the market. This ensures that the inventory is always 100% accurate and that "abandoned carts" don't bleed the operator's profit. Every transaction also leaves a rich Financial Tracepoint, storing market rates and operational metadata in native JSONB format for a perfect audit trail. This is what I call "Digital Concrete." I build systems that are rigid in their integrity but fluid in their scale. The Saldovia Engine is designed to handle 10 trips or 10,000 trips a day with zero changes to the core logic. I specialize in taking messy, manual business processes and turning them into surgical, high-performance automation. If your current infrastructure feels fragile, it’s because it lacks a solid architectural foundation. Let’s build your next system on concrete.
1
1
54