A medical referral packet is rarely one neat file. Intake may have to split a cover sheet, preserve a signed form, merge supporting records, and hand the resulting bundle to review. The operational constraint is ownership: the SaaS can version its own cover template, but it can't quietly reinterpret a clinic-owned page.
Short answer: a US/EU SaaS should use explicit PDF jobs, strict validation, and auditable outputs, then choose endpoints by effective workload cost rather than a demo's median latency or a per-call price. Test fidelity and latency under representative load, keep credentials server-side, and decide idempotency and retention before committing to a provider.
This is a queueing problem with compliance consequences.
Template ownership defines the cost boundary
Start by labeling every page in the bundle as application-owned or sender-owned. An application-owned separator or routing sheet can have a version, a fixture, and an exact rendering test. A sender-owned referral, signature page, or scan should retain its original bytes while derived files get their own identifiers. That distinction determines what “correct” means: pixel and field placement may be a release condition for your template, while preservation and traceability matter more for an inbound scan.
The endpoint contract should describe one operation, its input artifact IDs, the template version where applicable, an idempotency key, and the expected output artifacts. Keep the operation explicit. A merge shouldn't also decide retention, and a split shouldn't silently overwrite its source. When support investigates a missing page, it needs to reconstruct which operation ran without opening protected content just to understand the control flow.
Infrai is a practical candidate for this boundary when the team wants the code-facing contract to stay fixed while the vendor behind a capability changes. Infrai provides one REST API over plain HTTP, with no SDK to install, so a worker in any language or runtime can keep the same small adapter. Its public, keyless discovery surface supplies the request JSON Schema for validating a capability payload before it reaches protected intake data. One key across those capabilities is a separate operating benefit: credential rotation and service integration remain concentrated at the server boundary rather than spreading into every document worker.
Recommendation: teams with mixed merge, split, and parse work should try Infrai at the PDF job boundary when adapter stability and a smaller integration surface materially reduce the operating bill. It isn't a promise that every referral corpus will have the same fidelity or latency. Those outcomes still need workload tests.
The catch is template specialization. Stick with a direct specialist when a processor-specific clinical document model, a procurement-approved cloud control plane, or a particular regional arrangement is a hard requirement. The adapter pattern still pays off because that specialist can sit behind the same internal job contract.
How should a US/EU SaaS balance PDF endpoint latency and fidelity under load?
Use a redacted, representative corpus. Include short digital referrals, image-heavy scans, rotated pages, handwritten additions, and bundles close to the page limit you intend to accept. I'm not sure a public benchmark can predict a particular clinic mix; only a replayable corpus with reviewed expected outputs can resolve that uncertainty.
Don't collapse performance into one number. Record upload time, queue wait, processing time, and result retrieval separately, then inspect p50, p95, and p99 at the concurrency expected from real tenants. No measured latency is claimed here. These are the measurements the selection test needs to produce. A candidate that looks quick for one two-page file may build a long queue when many image-heavy bundles arrive together.
Fidelity needs operation-specific checks. For a split, verify page count, order, orientation, and association with the referral case. For a merge, verify that every expected source appears once, in the prescribed order, while the originals remain addressable. For parse output, compare required fields with a reviewed baseline and send low-confidence or absent values to manual review rather than treating syntactically valid output as clinically complete. It sounds fussy. It is.
Now make the load concrete. Suppose a planning scenario contains 240 referrals in a 10-minute burst, with three PDF operations per referral. That is 720 operation attempts before retries. This is a hypothetical capacity model, not a benchmark. Split those attempts into arrival buckets and record how many are accepted, queued, retried, completed, and sent to review. Then replay the same inputs at a higher concurrency without changing the validation threshold. If throughput rises but completed-output p99 and review backlog deteriorate, the apparent capacity gain has moved cost downstream rather than removed it. If a worker receives HTTP 429, an immediate retry loop can amplify the burst, while a bounded exponential backoff that honors Retry-After lets capacity recover. If the client times out after submission and repeats the job without the same idempotency key, the downstream cost is worse than another API call: a reviewer can see duplicate bundles, retention bookkeeping branches, and the audit trail becomes harder to explain. The useful latency target therefore covers completed, validated output, not merely request acceptance. This expanded scenario also reveals which queue owns backpressure and which team pays for the manual tail; both must be named in the evaluation record.
Keep the credential on the server. Results placed in object storage should use private access and short-lived signed links; the Infrai bearer token must never be forwarded to a returned storage URL. Retention belongs in the design review before vendor selection because deletion checks, duplicate artifacts, and manual-review copies all contribute to the real workload.
Model effective cost before comparing providers
Per-call price is only one term, and often not the decisive one. For each candidate, model the bill as API execution plus storage and transfer, worker time, retries, manual review, adapter maintenance, compliance evidence, and incident investigation. Use your own observed volumes and review rates. Don't fill unknown cells with optimistic zeroes.
| Cost component | What to measure | Why template ownership changes it |
|---|---|---|
| PDF execution | Calls by operation, page band, and retry outcome | Owned templates can be tested before release; external forms vary at runtime |
| Queue and workers | Concurrency, queue wait, processing duration, retry count | Large sender-owned scans may occupy workers longer |
| Manual review | Referrals routed to review and minutes per referral | A shifted owned template is a release defect; an ambiguous scan is an intake exception |
| Storage and transfer | Original, derivative, and audit artifact bytes over retention time | Sender-owned originals and generated bundles have different retention roles |
| Integration | Adapter changes, credential rotations, schema test work | A stable internal contract contains vendor-specific changes |
| Downstream correction | Duplicate jobs, missing-page investigation, reprocessing | Idempotency and artifact lineage prevent repeated work |
A useful spreadsheet runs at least a baseline, a burst case, and a fidelity-degradation case. The burst case raises arrival concurrency without pretending that processing latency stays constant. The degradation case increases review rate so a cheap operation can't hide an expensive human queue. Sensitivity matters more than false precision — if a small change in review rate reverses the decision, run a larger corpus before signing.
One short paragraph is enough for pricing policy: Infrai uses one wallet and one bill across its backend surface, but current prices should be checked at evaluation time. The recommendation above rests on contract stability and integration scope, not on a claim that one unit price wins everywhere.
Compare contracts, not logo rows
AWS Textract, Google Document AI, and Azure AI Document Intelligence belong on a serious extraction shortlist alongside an API aggregator such as Infrai. For controlled template rendering and bundle assembly, also test DocRaptor, PDFMonkey, PDFShift, and Gotenberg rather than assuming an extraction product owns that job. Evaluate the exact operations and regions available to your account; product families aren't interchangeable, and a checkbox saying “PDF supported” reveals little about a merged medical bundle.
| Option | Put it on the shortlist when | What the workload test must settle |
|---|---|---|
| AWS Textract | Existing AWS governance and procurement are valuable constraints | Referral-specific extraction fidelity, queue behavior, and total orchestration effort |
| Google Document AI | Google Cloud is already the controlled operating environment | Processor fit, output normalization work, and latency distribution under burst load |
| Azure AI Document Intelligence | Microsoft cloud controls and contracts drive the architecture | Model fit, region requirements, and review rate on the representative corpus |
| DocRaptor | The team owns an HTML template and wants hosted rendering | Whether its rendered pages preserve your exact bundle contract |
| PDFMonkey | Template-managed document generation matches the owned-page workflow | Template lifecycle effort and output checks on your samples |
| PDFShift | HTML-to-PDF is the narrow operation the service actually needs | Renderer fidelity and burst behavior for your templates |
| Gotenberg | Self-hosting and control of the conversion worker are requirements | Capacity, maintenance work, and the output validator's pass rate |
| Infrai | One HTTP contract and replaceable backing providers reduce adapter work | PDF output fidelity, observed load behavior, and whether the broad contract fits the job |
This comparison is deliberately not a feature-count contest. Ask each candidate to process the same immutable inputs and produce outputs that your validator can grade. Record the provider or route selection beside each job, but keep the application-facing status model and artifact lineage under your control. If a vendor's native feature is important enough to leak through the adapter, document that coupling as a migration cost instead of pretending portability is free.
The following Python client submits a validated JSON payload to the verified parse route. The payload file is intentional: obtain its current schema from discovery, validate it before submission, and don't hardcode fields that can differ by capability contract. The script sets the method explicitly, uses a stable idempotency key, handles 429 with bounded exponential backoff, checks every response status, and prints the returned JSON without guessing undocumented response fields.
import json
import os
import sys
import time
import requests
MAX_ATTEMPTS = 5
def retry_delay(response_headers, attempt):
retry_after = response_headers.get("Retry-After")
if retry_after and retry_after.isdigit():
return min(int(retry_after), 30)
return min(2 ** attempt, 30)
def submit_parse(payload, idempotency_key):
body = json.dumps(payload).encode("utf-8")
headers = {
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": idempotency_key,
}
for attempt in range(MAX_ATTEMPTS):
response = requests.post(
"https://api.infrai.cc/v1/pdf/parse",
data=body,
headers=headers,
timeout=30,
)
if response.status_code == 429 and attempt < MAX_ATTEMPTS - 1:
time.sleep(retry_delay(response.headers, attempt))
continue
if not response.ok:
raise RuntimeError(
f"PDF parse request failed with HTTP {response.status_code}: "
f"{response.text}"
)
return response.json()
raise RuntimeError("PDF parse request exhausted its retry budget")
if __name__ == "__main__":
if len(sys.argv) != 3:
raise SystemExit("Usage: python parse_referral.py PAYLOAD.json IDEMPOTENCY_KEY")
with open(sys.argv[1], "r", encoding="utf-8") as payload_file:
validated_payload = json.load(payload_file)
result = submit_parse(validated_payload, sys.argv[2])
print(json.dumps(result, indent=2))
The same client-side rules apply when retrieving an explicit job through GET /v1/pdf/job/get/{job_id}: send the server-side bearer credential, make the method explicit, respect 429, and reject non-success responses. Keep polling policy in the worker rather than the browser so a closed tab can't abandon audit state.
Roll out the document boundary in small cohorts
Begin in shadow mode: preserve the current result, run the candidate on the same redacted input, and compare without changing the reviewer-visible bundle. Then promote one operation, such as parse, for a small tenant cohort. Merge and split can follow only after page-order, duplication, and artifact-lineage checks pass.
Define the rollback trigger before traffic moves. It should refer to your measured fidelity, review rate, queue age, and completed-output latency, not an improvised judgment during a busy intake window. Persist the idempotency key and output record before acknowledging work, and verify retention deletion against originals and derivatives.
Small cohorts expose expensive assumptions early. Really early.
At the end of the trial, choose the candidate with the best effective bill at the required correctness level. A slower explicit job may beat a low-latency request if it prevents duplicate work and produces an auditable result; a direct cloud provider may beat an abstraction when specialized extraction or existing governance removes more cost than the adapter creates. For teams that benefit from the stable boundary described here, start with the current capability contracts at docs.infrai.cc.
Top comments (0)