easydocforms
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).
- API reference: https://easydocforms.com/docs/api
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_refmust 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