Integrating without an API: email as the contract
What to do when a counterparty offers no API: email as the data source, per-channel adapters, idempotency, and the limits of browser automation.
TL;DR. Half the processes in a small or mid-sized business depend on a counterparty that offers no integration: the platform has no partner API, the supplier has only a web portal, the carrier sends emails. The data still arrives machine-readable — as email. You can build a dependable integration on that, provided three things go in from day one: an adapter per channel, a stable event identifier, and cancellations handled as seriously as confirmations.
When there is no API and there won't be
The usual shape: availability, orders, or shipments live on several platforms at once, and each one knows only about itself. Until the data is pooled in one place, the same slot, item, or vehicle gets sold twice.
The standard answer is an API integration. It runs into the fact that some counterparties simply have no partner API — no event feed, no availability control. What's left is walking the web portals by hand after every event, which is work no one performs without misses.
But such a platform usually does have a machine-readable output after all. It's the notification email it sends on every event. It lands in a predictable mailbox, carries the fields you need, and arrives at the moment of the event rather than on a polling schedule.
Email here isn't a workaround — it's a deliberately chosen data source. The distinction matters: a workaround gets written in a hurry and never maintained, a data source gets designed.
What to build in from the start
An adapter per channel. Every platform differs: one attaches an ICS file, another sends HTML with the data buried in a template's markup, a third distinguishes a cancellation from a confirmation only by the subject line. There is no such thing as a universal parser here. Split by channel, though, and a template change at one platform breaks one adapter instead of the whole intake — visibly, and immediately rather than a week later.
A stable event identifier. The costliest failure in this kind of integration is duplicates. An email can arrive twice; processing can die halfway and repeat. So every event needs a key that survives retries: the message id, the UID from an attached calendar file, or a combination. Idempotency isn't a nicety here — without it the calendar fills with phantom entries and trust is gone within the first week.
A mark on what's been processed. A parsed email gets labelled in the mailbox itself. That's both protection against double processing and a way to see with your own eyes what the system has actually seen and what slipped past it.
Cancellations as a first-class path, not an edge case. A missed confirmation gets noticed immediately. A missed cancellation gets noticed by nobody: the dates stay blocked, the slot never sells, and the loss surfaces at month end in the revenue figure. Cancellation handling goes into every adapter on day one, not later.
Writing back: where email stops
Pooling the data is half the job. The other half is closing the booked dates or positions on the remaining channels. Email can't do that — email comes from the platform, it doesn't go to it.
What's left is browser automation: a script that logs into the portal and performs the action the way a person would. And here it pays to separate two parts:
- The job queue, retries, and conflict detection — ordinary infrastructure. Written once, works for every platform, testable without a browser anywhere in sight.
- The per-platform script itself — the fragile part. The interface changes without notice and the script breaks.
Decoupling the two buys a useful property: jobs accumulate in the queue whether or not a script exists for that channel yet. Once one ships, the backlog runs without reworking the logic. Readiness is also worth tracking per channel: full cycle on one, intake only on another. Collapsing them into a single "the integration works" status is a reliable way to lose data quietly.
What this approach doesn't give you
- Any guarantee on format. The email template belongs to the platform, and it changes whenever the platform likes, asking no one. You need monitoring: an email arrived and the adapter couldn't parse it is an event you want to hear about immediately, not from a monthly report.
- Complete data. The email contains what the platform chose to put in it. If the field you need isn't there, there's nowhere to get it.
- Speed in both directions. Intake runs near real time; writing back through a browser is slower and exactly as reliable as someone else's interface is stable.
- Legal insouciance. Parsing emails in your own mailbox is ordinary work with your own data. Automating someone else's portal often runs into that platform's terms of use — worth reading before development, not after. Sometimes the right conclusion is to leave that step to a human.
Where else this fits
The pattern — email as data source, normalization, one database or calendar — carries over to any process where a counterparty offers no integration:
- marketplace notifications about orders and returns;
- carrier confirmations and shipment statuses;
- supplier exports that arrive as scheduled attachments;
- leads from third-party forms and aggregators landing in a shared inbox.
The tell is always the same: the event happens at the counterparty, arrives by email, and then somebody re-types it by hand.
How we did it
- Syncing availability calendars across channels with no API — per-channel adapters (ICS attachment, HTML template, cancellation by subject line), normalization into a common shape, one calendar as the source of truth, a write-back queue with retries.
- Ticket auto-routing — the adjacent problem: what to do with events once they're pooled in one place.
If your process depends on a counterparty that won't integrate — let's talk for 30 minutes.