Written by Technical Team | Last updated 12.12.2025 | 14 minute read
Integrating with Accuro EMR can unlock powerful workflows: appointment synchronisation, patient-facing portals, document exchange, task routing, and more. But the difference between a proof-of-concept and a production-grade integration is rarely the happy-path CRUD calls. What makes or breaks you in real clinics is resilience: tokens expire mid-session, networks wobble, gateways time out, and write operations can succeed “just enough” to leave you with confusing partial state.
This article focuses on building a robust Accuro EMR integration that behaves predictably under stress. The goal is not only to prevent outages, but to ensure your system fails safely, recovers quickly, and never compromises data integrity. We’ll look at the practical engineering patterns that address three of the most common operational pain points: token expiry, network failures, and partial writes.
In Accuro integrations, authentication is typically OAuth-based, and many API surfaces are scoped to different contexts (for example, provider-portal versus patient-portal flows). Tokens expiring is normal; treating expiry as an exceptional event is what causes avoidable incidents. A resilient integration assumes that access tokens are ephemeral, refresh tokens are sensitive, and any token can become invalid earlier than expected due to revocation, clock skew, user changes, or server-side policy updates.
The first hardening step is architectural: ensure that “token ownership” lives in exactly one place. If every microservice or worker process implements its own token refresh logic, you will eventually create thundering herds, race conditions, and inconsistent error handling. Prefer a single shared component (a token service or library) with clear guarantees: it returns a valid access token for a given tenant/user context, and it handles refresh behind the scenes.
A strong token service does more than “refresh when expired”. It uses a refresh window. Instead of waiting for a 401/403 to happen on production traffic, refresh proactively when the token is approaching expiry (for example, within the next few minutes). This prevents the worst-case scenario where multiple concurrent requests all discover expiry at the same time and stampede your refresh endpoint. You can still keep reactive refresh as a backstop, but proactive refresh reduces turbulence dramatically.
You also need concurrency control. Imagine 50 background jobs begin at 09:00 and all need the same provider-scoped token. If each job sees “token expires soon” and refreshes independently, you end up rotating tokens repeatedly, or invalidating each other’s refresh state. Solve this with a single-flight mechanism: one refresh attempt per token identity at a time, with other callers awaiting the result. In practice this can be a distributed lock (Redis, database advisory locks) or an in-process mutex if you have a single runtime instance. For multi-instance systems, distributed coordination is safer.
A subtle but important design decision is where you store tokens. Access tokens are short-lived and can be cached in memory; refresh tokens are long-lived and must be treated like credentials. Store refresh tokens encrypted at rest, scope them narrowly (per tenant, per user, per portal type), and implement rotation-aware updates: when you refresh and receive a new refresh token, commit it atomically and invalidate the old one. If your refresh token storage is eventually consistent, you can accidentally “lose” the rotated token and lock out your integration until a human reconsents.
Finally, treat authentication failures as an operational state, not a generic error. There’s a meaningful difference between:
Your code should classify these outcomes and respond accordingly: automatic refresh, exponential backoff, or “pause this integration and notify an administrator”. The worst behaviour is repeated retries with an invalid refresh token, which can trigger rate limiting and drown your logs while achieving nothing.
Token management keeps you authenticated; network hardening keeps you functional. In healthcare environments, you will see everything from pristine fibre connections to flaky VPNs, restrictive proxies, and intermittent DNS issues. The most dangerous mindset is assuming the network is reliable and the server is fast. Production-grade Accuro integrations are built on the assumption that every request can fail, and that your responsibility is to fail in a controlled and reversible way.
Start with timeouts. “No timeout” is not “more reliable”; it’s a slow leak that eventually exhausts thread pools, sockets, and worker capacity. You want a layered timeout strategy: connect timeout (establish TCP/TLS), request timeout (total time), and per-try timeout (how long each retry attempt is allowed). Keep them realistic: long enough for normal variance, short enough to protect capacity. If you don’t set timeouts explicitly, your HTTP client defaults may be unsuitable for a clinic-grade system under load.
Then implement retries, but only where they are safe. The key is to distinguish retryable failures (temporary network issues, 502/503/504 gateway errors, transient timeouts) from non-retryable failures (validation errors, authorisation issues, semantic conflicts). Even among retryable failures, you must consider whether the operation is idempotent. A GET is usually safe to retry; a POST that creates a record is dangerous unless you have idempotency controls (covered later).
To avoid amplifying outages, use exponential backoff with jitter. Exponential backoff reduces pressure on the API during incidents; jitter prevents your fleet from retrying in lockstep. Also cap retries: a small number of well-spaced attempts is better than dozens of rapid retries that turn a blip into an outage. When the API is genuinely down, you want the system to degrade gracefully, not to panic.
Circuit breakers turn “repeated failures” into a known state. If requests to Accuro are failing consistently, your integration should stop hammering the API and instead open the circuit: short-circuit calls for a cool-down period, return a controlled error to upstream components, and schedule a health probe to check when service returns. This protects both your infrastructure and the EMR environment, and it makes your system’s behaviour predictable during incidents.
A practical approach is to build a single “Accuro API client wrapper” used by all code paths. It should enforce consistent policies (timeouts, retry rules, backoff, circuit breaker thresholds) and attach correlation IDs for tracing. This wrapper becomes the place to encode the reality of the API and your environment, rather than leaving each engineer to reinvent resilience ad hoc.
Common, production-proven hardening behaviours include:
A final note: resilience is not just client-side. Plan for load shaping. If you have background synchronisation jobs, ensure they respect concurrency limits. A sudden spike in outbound requests can look like a denial-of-service from the EMR’s perspective, and if the API enforces throttling, your own retries can worsen the situation. Limit concurrency per tenant, prioritise interactive traffic over batch traffic, and queue non-urgent work rather than firing everything at once.
Network failures create a nasty class of bugs: the request may have been processed, but the response never arrived. From your system’s point of view it “failed”; from Accuro’s point of view it “succeeded”. If you then retry a non-idempotent write, you can create duplicates, conflicting state, or confusing audit trails. This is where replay safety and idempotency become essential.
The ideal solution is an explicit idempotency feature supported by the API itself (for example, an Idempotency-Key header). If an API doesn’t provide that guarantee end-to-end, you need to implement idempotency at the application level. The strategy depends on the type of record and the endpoint behaviour, but the principle is consistent: every write must have a stable, unique identity so it can be recognised as “already applied”.
A common pattern is to maintain a local “operation ledger”. Before you perform a write to Accuro, you record an operation ID (a UUID) along with the intended action, the target entity, and a hash of the payload. You then execute the call. If the call succeeds, you mark the operation as completed and store the remote identifier(s) returned by Accuro. If the call times out or fails in an ambiguous way, you do not immediately repeat the write blindly; instead, you consult the ledger and use a reconciliation method to determine whether the operation was already applied.
Reconciliation can be straightforward when your domain model allows lookups by stable external identifiers. For example, if you write a record that includes your system’s reference (a custom identifier, an external contact identifier, a note tag, or a deterministic title), you can search Accuro for that marker to decide whether the write is already present. Where Accuro records don’t allow such markers, you may need alternative strategies: comparing payload hashes, using timestamps cautiously, or relying on “create then update” workflows that are safer to replay.
For update operations (PUT), idempotency is more natural, but you still need to manage concurrent modifications. If two systems can update the same record, last-write-wins behaviour can silently overwrite changes. A hardened integration uses optimistic concurrency where possible: read the current state, compute the intended change, and apply it only if the base version matches expectations. If the API doesn’t support ETags or version headers, you can simulate a soft form of concurrency control by checking critical fields before applying updates and refusing to overwrite if the record has drifted.
For create operations (POST), one of the safest patterns is “deterministic create”. Rather than creating “a new record” with no stable identity, create a record that is keyed to a deterministic external identity. That might be a composite of tenant ID + local entity ID + record type. If you can embed that identity somewhere in the record, you can safely re-run the create call: if the record already exists, you can treat the operation as complete and move on. This is especially important for integrations that process message queues, where at-least-once delivery is the norm and duplicate processing must be harmless.
Finally, make your retries write-aware. Your HTTP layer should not blindly retry all requests. A hardened Accuro integration routes writes through an idempotency wrapper that decides whether a retry is safe, whether to switch to a “check status then continue” flow, or whether to pause and escalate.
Partial writes usually appear when a business action spans multiple API calls. For instance, you might create a record, then attach a document, then update metadata, then send a task or message. If the third step fails, you end up with Accuro containing a partially-completed artefact and your system unsure whether to roll forward, roll back, or retry.
It’s tempting to look for “distributed transactions”, but in practice you harden these workflows with deliberate state machines. Think of each multi-step workflow as a saga: a sequence of steps, each with a well-defined success condition and a compensating action (where safe), plus the ability to resume after interruption. You store the saga state in your own database, not in memory, so you can recover after process restarts and deploys.
The outbox pattern is especially valuable. Instead of performing side effects directly inside your primary transaction (for example, saving a patient update locally and immediately calling Accuro), you record the intent in an outbox table within the same database transaction that updates your own state. A background worker then reads the outbox and executes calls to Accuro with retries, idempotency controls, and visibility. This decouples user-facing operations from external reliability, and it prevents the dreaded “saved locally but never sent” gap caused by mid-transaction crashes.
You still need to handle the Accuro side being partially updated. That means you need a reconciliation process that can compare your system’s view of “what should exist” against “what does exist” in Accuro, then correct drift. Reconciliation should be planned from the beginning, not bolted on after an incident. The strongest integrations include a periodic job that samples recently changed entities and verifies that:
When reconciliation finds mismatch, you have options: re-apply the write (if idempotent), apply a compensating update, or escalate for human review. Healthcare workflows often require careful handling; sometimes the safest “compensation” is to post a clarifying note or create a task for a staff member rather than trying to delete or revert clinical content automatically.
Designing for partial writes also means planning for ordering and eventual consistency. If your system processes events (webhooks, message queues, scheduled sync), the same entity might be updated from multiple sources. You want deterministic rules: which source wins for each field, what happens when events arrive out of order, and how you prevent older updates from overwriting newer ones. A robust approach is to record a “source timestamp” and a “write generation” per entity, and to ignore stale events once a newer generation is committed.
In practice, the most reliable approach is to accept that multi-step EMR workflows are eventually consistent. Your integration should communicate that clearly in its own UX (if relevant), and it should ensure that eventual consistency never becomes eventual chaos. That means durable workflow state, resumable steps, careful retry rules, and reconciliation that turns rare edge cases into routine maintenance rather than emergencies.
Hardening isn’t complete until you can prove it works in production and recover quickly when it doesn’t. An Accuro integration operates in a clinical context where delays and confusion cost time, and time is scarce. Monitoring and incident response are not “nice to have”; they are core product features for any system that touches EMR data.
Start with structured logging. Every request to Accuro should include a correlation ID that is logged consistently across your services, queues, and workers. Log at the right level: enough detail to debug failures without leaking sensitive patient data. This typically means logging endpoint names, response status codes, latency, retry counts, and operation IDs—while redacting or omitting clinical payloads unless you have a controlled secure debugging mode.
Metrics are what turn anecdotes into engineering decisions. Track authentication and token events separately from general API traffic. If you see spikes in 401 responses, you want to know whether the issue is token refresh failures, clock skew, revoked consent, or a deployment bug. Similarly, track network errors distinctly from semantic 4xx failures. A rising trend of timeouts suggests network or capacity issues; a rising trend of 409/422 suggests data validation or concurrency problems; a rise in 429 suggests your throughput management needs work.
Alerting should be symptom-based and tenant-aware. A single clinic experiencing errors may indicate configuration issues; multiple tenants failing suggests a systemic outage. Make sure alerts don’t require an engineer to read 500 lines of logs to understand what’s happening. “Portal token refresh failing for tenant X” is actionable; “500 error occurred” is not.
Operational maturity looks like this:
Finally, conduct failure drills. Token expiry, DNS failure, and “response lost after successful write” are not rare in the long run; they’re inevitable. Simulate them in staging and occasionally in production via controlled chaos testing (for example, injecting timeouts in a small percentage of calls). The point is not to create drama—it’s to ensure your safeguards actually behave as intended when the unexpected happens on a busy Monday morning.
When you combine token lifecycle discipline, resilient networking, idempotent writes, saga-based workflow design, and strong observability, you end up with an Accuro EMR integration that is not merely functional, but dependable. It will still experience failures—every system does—but it will fail in ways that are contained, explainable, and recoverable, which is what clinicians and patients ultimately need from software that sits in the middle of care delivery.
Is your team looking for help with Accuro EMR integration? Click the button below.
Get in touch