1. Work
  2. Integrations and data platforms

One customer across many systems: billing and identity integration

Keeps one trustworthy customer identity in step across billing, website and support systems, with confidence-ranked matching, human corrections that stick, failures that reach people, and self-service billing where no card data touches the site.

Problem

A subscription services business held the same customer in several places: a billing platform (the source of truth), a payment provider, a help desk and customer-messaging platform, the company website's user store and the customer's own cloud workspace tenant. Nothing reliably linked the records. Details drifted, website accounts were created and upgraded by hand, corrections made by support staff never reached the other tools, and customers had no single place on the website to see their plan, trial, invoices and services.

Goal

One trustworthy customer identity across every system, kept in step automatically; website access that follows what each customer has actually bought; human corrections that stick without writing back to billing; failures that reach people instead of drifting silently; and a self-service billing area on the website where no card data ever touches the site.

My role

Worked on the customer registry and console API, and designed and built the multi-platform record sync service, the subscription-to-membership sync (run in production), the self-service billing dashboard and the purchases widget. On the customer portal page, took over an existing integration built by another developer, deployed it to production and reworked its domain security scorecard to load in the background from a cache, with deduplication and theme-aligned styling.

Solution

Five cooperating pieces.

A customer registry and console API: administration of customers' cloud workspace tenants, confidence-ranked record matching with a human review queue, and a transactional outbox for reliable fan-out.

A record sync service: polls the billing platform, detects changed records by hash and pushes them independently to the website user store and the messaging platform, with field-level overrides from support agents, retries, alerts and an operator dashboard.

A subscription-to-membership sync: an hourly website job that links or creates website users in transactional batches and maps each customer's active subscriptions to a membership role.

A self-service billing dashboard and purchases widget: live plan, trial, invoice and purchase views, with every money-moving action handed to the payment provider's hosted pages.

Portal service and domain scorecard widgets: a services table plus per-domain security scorecards that load in the background from cached checks.

How it works

Registry and outbox.

A website proxy holds the API key on the server, so no key reaches the browser.

Tenant administration (users, groups, aliases, devices, security posture, storage, audit data) runs through two authorisation paths, delegated admin access and per-customer OAuth, with refresh tokens encrypted at rest.

Every inbound record passes a ranked matching ladder: external identifier, then primary email, then user email, then a single routable domain. Ambiguous domain matches go to a human review queue, and free-mail domains never merge two customers.

Registry changes are written to an outbox table in the same transaction. A worker claims events with row locks that skip claimed rows, calls the help desk without holding a lock, retries and reclaims orphaned claims.

Security, device and DNS signals become pass, warn or fail flags in the help desk; payment webhooks are signature-verified; a small browser extension reports device health.

Record sync service.

A scheduled polling job pulls billing records in throttled batches under a file lock, so runs never overlap.

Each record is normalised, mapped and hashed; unchanged records are skipped, and a full-sync mode forces everything.

Changed records go to the website user store and the messaging platform separately, each result logged on its own, so one failure never blocks the other.

When an agent edits a contact in the messaging platform, a signed webhook records a field-level override. Later syncs apply it on the website and write a visible mismatch note. The billing platform is never written to.

Failures retry a limited number of times, then are marked permanent and trigger alerts. An operator dashboard with viewer, operator and admin roles, a dry-run mode and a go-live checklist protect production.

Subscription-to-membership sync.

An hourly job reads the next page of billing customers with a resumable cursor.

Each batch runs in one transaction: bulk-load mappings and matching users, link, update or create accounts, bulk-insert new mappings.

Active products map to a small set of membership roles that other site features read; every run posts an outcome summary to team chat.

Design safeguards: a full sync pages one consistent customer entity, sign-in emails are never overwritten from billing (only display fields flow one way), and every API response is normalised before processing.

Billing dashboard and purchases widget.

A shortcode mounts a framework-free JavaScript app that reads the signed-in user's billing state; the server resolves the login to a payment-provider customer and caches the result briefly.

The app renders one of five states: trialing, active (with an invoice table), past due, cancelled, or no billing account.

Upgrade and manage buttons open the provider's hosted checkout or customer portal, so card entry happens only on the provider's pages.

The purchases widget merges subscriptions and paid one-time invoices into one model, with product names from a separate cached lookup.

Portal widgets. A services table enriches the customer's products with status and billing dates, and one security scorecard per domain renders at once, then fills in its certificate, HTTPS, header and DNS checks in the background from a day-long cache.

Technical challenges

Matching records across systems without false merges: a ranked ladder that refuses to guess, a human review queue and free-mail exclusion.

Reliable fan-out without dual-write inconsistency: transactional outbox, lock-skipping claims, no lock held during network calls, orphan reclaim.

Change detection when the source has no reliable change timestamps (content hashing), and isolating failures per target with correct partial-success records.

Precedence between a read-only source of truth and human corrections downstream, without a write-back loop (field-level overrides plus mismatch notes).

Keeping sign-in identity stable while display fields sync one way.

Processing a whole customer base within PHP execution limits (paging, a resumable cursor, one transaction per batch) and preventing overlap between scheduled and manual runs.

Fresh billing data without slow pages (a short per-customer cache), and keeping card handling and its compliance scope off the site.

Supporting two authorisation models for tenant administration and storing long-lived tokens securely.

Moving slow outbound checks off the render path and bounding them with a cache.

Capabilities

  • Cloud workspace tenant administration
  • Unified customer registry with confidence-ranked matching and a review queue
  • Reliable event fan-out with retries
  • Security and device health flags inside the help desk
  • Hash-based one-way sync to two targets
  • Agent override capture with mismatch notes
  • Role-based operator dashboard with dry-run and go-live checks
  • Automatic website account creation and subscription-to-membership role mapping
  • CRM plan push and chat run summaries
  • Live subscription, trial and invoice views
  • Hosted upgrade and self-service billing management
  • Unified purchases table
  • Per-domain security scorecards
  • Encrypted token storage

Technology

  • Python 3.12 with FastAPI and Pydantic
  • SQLAlchemy in async mode with Alembic
  • PostgreSQL and a document database
  • Symmetric encryption for stored tokens
  • PHP 8 with Composer
  • Guzzle and Monolog
  • MySQL with transactions and bulk upserts
  • WordPress plugin and theme APIs
  • WordPress scheduled jobs and CLI commands
  • REST routes and shortcodes in WordPress
  • WordPress transients
  • WordPress custom roles and tables
  • JavaScript with no framework
  • Cloud workspace admin APIs with delegated access and OAuth
  • Payment provider subscriptions and hosted checkout
  • Payment provider customer portal and webhook APIs
  • Billing platform REST API
  • Customer-messaging platform REST API
  • HMAC-signed webhooks
  • Browser extension
  • Docker and serverless containers
  • pytest

Impact

The design gives each customer one identity across billing, payments, support and the website: website access follows purchases automatically, security and device health sit in front of support staff inside the tool they already use, agent corrections are preserved, and failures reach people instead of drifting. The self-service billing area is designed so customers can see and manage their plan and invoices without card data touching the site. No metrics are claimed.

Skills demonstrated

  • Integration architecture
  • Data synchronisation, idempotency and change detection
  • Conflict and precedence design
  • Batch processing within platform limits
  • Payment and subscription integration
  • Webhook security
  • Caching slow outbound checks off the render path
  • Data-integrity safeguards
  • Taking over and improving another developer's production code

Demo

Planned

One fictional online learning company, with about 40 invented customer companies arriving from three mock systems (a billing API, a website user store and a messaging contacts API), using reserved test domains only. First, matching: records arrive with hard cases (two companies sharing a free-mail address, two on one domain, a changed email, a missing external identifier) and the ladder decides match, create or review, with a small review-queue screen; an outbox worker then processes events against a mock downstream that fails intermittently, retrying and reclaiming an orphaned claim. Second, sync: a run, then a few source edits so only those records sync again by hash; a simulated agent edit becomes an override with a mismatch note; one target fails while the other succeeds and an alert fires. Third, the billing page switching between the five states for invented customers with made-up plans and a fake invoice list, plus a sequence diagram of page load, cache and provider lookup.

Not built yet. A demo here uses only invented names and data.

All work