← Blog

Process automation

Prescription renewals: 27 minutes to 90 seconds with n8n

A 41-person veterinary group in Groningen was drowning in prescription renewals. One n8n flow into IDEXX and Exact Online took it from 27 minutes to 90 seconds.

Jacob Molkenboer· Founder · A Brand New Company· 10 Jun 2026· 9 min
Weathered prescription pad with green tab, brass fountain pen, amber vial on ivory paper, side window light.

Monday, 8:15 AM. The lead receptionist at a veterinary clinic in Groningen opens her inbox. Thirty-four prescription renewal requests are waiting: phone messages transcribed by the answering service over the weekend, six portal submissions, eleven emails forwarded by other clinics in the group. She knows what the day looks like now. Twenty-seven minutes per request, give or take. Lunch will be at her desk.

Multiply that across twelve clinics and the math gets ugly. The group employs forty-one people across receptionist, vet, and vet-tech roles. Prescription renewal handling was eating roughly two full-time equivalents before anyone touched the technology.

We rebuilt the workflow on a single self-hosted n8n flow this spring. End-to-end handling is now ninety seconds for the auto-eligible cases, which are about 78% of the volume. This post walks through where the original 27 minutes went, what the n8n flow actually does, what we tried first that did not work, and the two things that broke in the first fortnight.

Where the 27 minutes actually went

The 27-minute number was not lazy work. We sat with the receptionist team for two mornings before we wrote any code. The time breaks down roughly like this.

  • 4 minutes parsing the request, often a voicemail transcript, into a pet, an owner, and a medication.
  • 5 minutes inside IDEXX to find the patient, pull the chronic medication record, and check the date of the last consultation for that condition.
  • 3 minutes deciding under Dutch veterinary regulations whether the vet can sign off remotely, or whether the owner needs to book a fresh consult.
  • 6 minutes waiting on or paging the vet, who is mid-consult, then waiting again for them to look at the file.
  • 4 minutes generating the prescription PDF from a Word template, fixing the formatting that breaks when Word talks to PDF, attaching it to an email, sending it.
  • 3 minutes creating the invoice line in Exact Online, copying the owner's debtor number across, marking the renewal closed in IDEXX.
  • 2 minutes of context-switching tax: phone ringing, walk-in arriving, kettle.

None of these steps are dumb. Each one exists for a reason. Cumulatively they meant a receptionist could handle maybe twelve requests in a morning, and the queue grew faster than they shrank it.

The constraint nobody can automate around

Before we touched a single API, we agreed on the non-negotiable. A licensed veterinarian must approve every renewal. Dutch veterinary law requires it, and the KNMvD guidelines are unambiguous. Software does not approve prescriptions. The vet does. The system's job is to put a one-click decision in front of the vet with all the context they need, and to disappear once they click.

That framing made the rest of the design simple. We were not trying to remove the vet from the loop. We were trying to remove every minute around the vet.

What we tried first that did not work

The first version, built in week one as a throwaway, was a Zapier MVP wired to a shared IMAP inbox and a Google Sheet. It did three things badly. It could not call the IDEXX API in a way that respected per-clinic rate limits. It could not be put behind the group's own VPN, so patient data was crossing infrastructure boundaries we did not control. And the price scaled per task with no ceiling, which on 34-request Mondays got real.

We killed the MVP after eight days. The Sheet had been useful for one thing: it gave the team a place to see the queue, which the receptionists had never had before. That alone reduced perceived chaos by about a third. We carried that pattern (one queue, visible to everyone) into the production build.

The n8n flow, end to end

One flow, self-hosted on a small VPS in Amsterdam, behind the practice group's own VPN. We picked n8n over Make or Zapier for three reasons: self-hosting (patient data never leaves EU infrastructure the group controls), readable JSON exports under git, and the freedom to drop into a Function node when a vendor API does something weird. All three mattered within the first month.

The flow has six stages. They are genuinely sequential, so a numbered list earns its keep.

  1. Intake. A single inbound email address (recepten@) and a portal form both write to the same Postgres table. The voicemail transcription service writes there too. One queue, three sources.
  2. Parse. A small classifier extracts pet name, owner email or phone, medication, and dose. Confidence below 0.85 routes to a human-review lane. Roughly 14% of requests land there.
  3. Lookup. n8n calls the IDEXX practice management API, finds the patient, and pulls the chronic medication history plus the date of the last consultation tagged with the relevant condition.
  4. Gate. If the patient was seen within 12 months for the matching condition, the request is auto-eligible. If not, n8n sends the owner a pre-filled Calendly link for the right consult type with the right vet, and closes the request as “consult required”. No prescription, no vet ping, no further work.
  5. Vet approval. For auto-eligible requests, n8n posts a Slack message to the duty vet's channel with the patient summary, last consult notes, requested medication, and two buttons: approve and reject. The approve button hits a webhook back into the same flow.
  6. Fulfilment. On approve, n8n renders the prescription PDF from a templated HTML file (we use a small Puppeteer service, not Word), emails it to the owner, creates the invoice line in Exact Online, and writes the closure note back into IDEXX.

The vet's part of the workflow is one Slack message and one click, usually between consults. That is the only synchronous human step. Everything else runs while she is in the room with the next dog.

For anyone curious what the Exact Online invoice call looks like once you have a refresh token in hand, it is roughly this:

curl -X POST \
  "https://start.exactonline.nl/api/v1/${DIVISION}/salesinvoice/SalesInvoices" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "OrderedBy": "'"${DEBTOR_GUID}"'",
    "Journal": "70",
    "SalesInvoiceLines": [{
      "Item": "'"${ITEM_GUID_RX_RENEWAL}"'",
      "Quantity": 1,
      "Description": "Herhaalrecept '"${MEDICATION}"' - '"${PET_NAME}"'"
    }]
  }'

What ninety seconds buys you

The 90-second figure is wall-clock from intake to the owner receiving their prescription PDF, for the 78% of requests that are auto-eligible. The breakdown:

  • Around 8 seconds for parse, lookup, and gate.
  • Around 60 seconds median wait for the duty vet to see and click. The 95th percentile is closer to four minutes, which is still fine.
  • Around 22 seconds for PDF render, email send, Exact Online invoice line, IDEXX closure.

For the 22% that need a consult, the flow closes inside two seconds with a Calendly link in the owner's inbox. From the receptionist's view, those requests never existed.

Takeaway

You do not automate the vet's judgement. You automate the twenty-five minutes of file-pulling and form-filling that surround the vet's judgement.

The two things that broke in the first fortnight

Nothing ships clean. Two failure modes showed up in week one and week two, and both are worth naming because they will happen to anyone wiring this stack together.

Exact Online's session tokens

The Exact Online OAuth flow issues a refresh token that expires after thirty days of disuse. The first weekend with no invoices generated (a quiet bank holiday) was enough to invalidate it. Monday morning, twelve clinics had a six-hour invoicing gap before anyone noticed. We fixed it with a daily cron that calls a low-cost endpoint just to keep the session warm, and a Slack alert if any 401 comes back from the Exact node.

IDEXX rate limits during morning peak

Between 08:00 and 09:30 every clinic in the group is checking patients in, running diagnostics, and writing notes against IDEXX. Our flow's lookup calls were getting 429-rate-limited in that window. We added a Redis-backed queue with a 250 ms minimum interval per clinic ID, and rate-limit retries with exponential backoff. The owner does not notice if their renewal email arrives at 09:32 instead of 09:01.

Warning

If you build this and your practice management system has a daily peak window, test the integration during that window before you ship. Off-hours performance lies to you.

What this is not

This is not an AI agent. There is no model in the loop making clinical decisions. The classifier in stage two is a small open-weight model running locally, used only to extract structured fields from messy free text. Everything downstream is deterministic n8n. We kept it that way on purpose.

There is a recurring debate on Hacker News this month about whether AI progress is slowing down, and a separate thread about the tools people have built for themselves since LLMs got useful. From inside the kind of work we ship for operations teams, both threads feel a little miscast. Most of the durable wins still come from boring deterministic integration: one workflow tool, two vendor APIs, a careful regulatory gate, a clear human-in-the-loop step. The flashy parts of the AI stack are useful, but they are rarely the bottleneck.

How to read this against your own ops

If you run a multi-site operation in any regulated industry (veterinary, dental, legal, accounting, healthcare adjacent) the shape of this problem will look familiar. The questions to ask yourself this week:

  • Which of your team's recurring tasks have a clear regulatory or judgement gate that a human must own? Mark those. They are not automation targets, they are pivot points.
  • What does the work look like in the twenty minutes around that gate? That is your target.
  • Which two systems are your front-desk team alt-tabbing between all day? Those are your integration endpoints.
  • What is the smallest unit of work you can route end-to-end without touching a human, once the gate is cleared?

The win at the Groningen group was not technical sophistication. The hardest day was the two mornings we sat behind the reception desk with a notepad before writing any code. The flow itself is about 340 lines of exported n8n JSON and a Puppeteer service of around 80 lines. The credential vault, the rate-limit shim, and the monitoring took longer than the business logic, which is normal.

The unexpected second-order effect

When we built this process automation for the practice group, the thing we did not expect was how much of the value showed up in the consult-required path. Twenty-two percent of renewal requests now turn into booked appointments inside a day, where previously they sat in a vet's to-do list until someone called the owner back. The flow surfaced demand the team had not seen, because nobody had had time to follow up.

If you want the five-minute audit version: open your team's most reliable recurring complaint, time the slowest version of it with a stopwatch this week, and write down which two systems they are alt-tabbing between. That list is the whole brief.

Key takeaway

You do not automate the vet's judgement. You automate the twenty-five minutes of file-pulling and form-filling that surround it.

FAQ

Why n8n and not Zapier or Make?

Self-hosting kept patient data on infrastructure the practice group controls, the flow exports as readable JSON under git, and Function nodes let us patch vendor API quirks without leaving the tool.

How does the system stay legal under Dutch veterinary rules?

It does not approve any prescription. A licensed vet clicks approve on every renewal via Slack. The flow only handles intake, lookup, the consult-required gate, fulfilment, and billing.

What stops a pet owner from gaming the system?

The gate checks the date of the last consultation tagged with the matching condition inside IDEXX. If it is older than twelve months, the request becomes a booking link rather than a prescription.

How long did the build take?

Two mornings of observation, eight days on a throwaway Zapier MVP we then killed, and roughly three weeks on the production n8n flow including the Exact Online and IDEXX integrations and monitoring.

process automationintegrationsworkflowcase studyoperationstooling

Building something?

Start a project