0.0
The project is in a healthy, maintained state
EasyDocForms turns a blank PDF intake form into a hosted, mobile-friendly fillable form and returns the completed, pixel-exact PDF plus structured JSON answers. This gem wraps the Partner API: import a blank PDF, mint a hosted patient fill link, receive signed webhooks, and retrieve submissions. Zero runtime dependencies.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

easydocforms

Gem Version CI

The official Ruby SDK for the EasyDocForms Partner API.

EasyDocForms turns a blank PDF intake form into a hosted, mobile-friendly fillable form — and returns the completed, pixel-exact PDF plus structured JSON answers. The API wraps the same document-understanding pipeline EasyDocForms runs in production for healthcare intake: import a blank PDF, wait for the template, mint a hosted fill link, hand it to a patient, then retrieve the results.

Zero runtime dependencies — standard library only (net/http, json, openssl).

Install

# Gemfile
gem "easydocforms"

Quickstart

API keys are created in the EasyDocForms app under Settings → Integrations → Partner API (shown exactly once).

require "easydocforms"

client = EasyDocForms::Client.new(ENV["EASYDOCFORMS_API_KEY"])
pong = client.ping
puts "org #{pong[:org_id]}, key #{pong[:key_name]}, scopes #{pong[:scopes].join(", ")}"

The full loop

# 1. Import a blank PDF (async — returns immediately).
import = client.create_import(
  pdf_url: "https://example.com/new-patient-intake.pdf",
  filename: "new-patient-intake.pdf",
  blank_form_attestation: true # you attest the PDF is a blank template — no PHI
)

# 2. Wait for processing (typically 1–10 minutes). Imports never fail for
# quality reasons: the template is always created, and :review_required tells
# your staff what to double-check in the EasyDocForms editor.
import = client.wait_for_import(import[:import_id])
raise import[:error] if import[:status] == "failed"

# 3. Mint a hosted fill link and hand it to the patient. No EasyDocForms
# account needed on their side.
link = client.create_fill_link(
  template_id: import[:template_id],
  external_ref: "visit-8675309" # your correlation id — must not contain PHI
)
puts "send the patient to: #{link[:url]}"

# 4. When the patient submits (see webhooks below), fetch the results.
submission = client.get_submission(submission_id)
submission[:answers] # => { field_id => value, ... }

File.binwrite("completed.pdf", client.download_submission_pdf(submission_id))

# Or get a ~10-minute signed URL that needs no Authorization header — safe to
# hand to a browser or EMR without embedding your API key.
begin
  pdf_link = client.get_submission_pdf_link(submission_id)
rescue EasyDocForms::PDFPendingError
  # The frozen artifact isn't ready yet; use download_submission_pdf instead.
end

Webhooks

Register a delivery URL, store the one-time whsec_* secret, and verify every delivery's X-EDF-Signature header against the raw request body:

result = client.create_webhook(url: "https://your-app.example.com/webhooks/easydocforms")
result[:secret] # shown only once — store it now
event = EasyDocForms::Webhook.construct_event(
  payload: request.body.read,
  header:  request.headers[EasyDocForms::Webhook::HEADER],
  secret:  ENV["EASYDOCFORMS_WEBHOOK_SECRET"]
)

case event[:event]
when "submission.created"
  # PHI-minimized: no answers in the payload. Fetch them with your API key
  # via event[:data][:submission_id].
end

Verification recomputes an HMAC-SHA256 over the raw body, compares in constant time, and rejects timestamps more than 5 minutes from now (configurable via tolerance:). A failed check raises EasyDocForms::SignatureVerificationError — respond 400 and move on.

Rails

rails generate easydocforms:webhook

creates a verified receiver controller at app/controllers/easydocforms_webhooks_controller.rb and prints the route + credentials setup.

Error handling

API failures raise typed subclasses of EasyDocForms::APIError, each carrying status_code, the server's message, and a machine-readable code on authorization failures:

Error When
AuthenticationError 401 — missing, invalid, or revoked key
PermissionError 403 — code is SCOPE_REQUIRED or PARTNER_API_NOT_ENABLED
NotFoundError 404 — no such resource in your organization
PDFPendingError 409 on get_submission_pdf_link — fall back to download_submission_pdf
RateLimitError 429 — back off and retry

The SDK does not retry automatically.

PHI boundary

  • Imports are blank forms only. Every import requires blank_form_attestation: true, asserting the PDF contains no patient-identifiable information.
  • external_ref must never contain PHI. It is an opaque correlation id echoed on submissions and webhook events.
  • Webhook payloads are PHI-minimized by design — ids and retrieve URLs, never patient answers. Answers are only available over the authenticated API.

License

MIT