Skip to content

Add questionnaire_webhook plugin - #413

Open
hardylt wants to merge 1 commit into
Medical-Software-Foundation:mainfrom
hardylt:questionnaire_webhook
Open

Add questionnaire_webhook plugin#413
hardylt wants to merge 1 commit into
Medical-Software-Foundation:mainfrom
hardylt:questionnaire_webhook

Conversation

@hardylt

@hardylt hardylt commented Jul 20, 2026

Copy link
Copy Markdown

What this plugin does

questionnaire_webhook listens for questionnaire commits (QUESTIONNAIRE_COMMAND__POST_COMMIT), picks out specific answers, and POSTs them to an external endpoint.

It ships with two working example branches, both drawn from a real deployment:

Branch A — CCM-eligible encounters. An RDP Encounter Type questionnaire where a particular question carries a particular answer sends the note id and patient id to a CCM endpoint.

Branch B — prior-authorization medication fields. A questionnaire whose title starts with PA has its medication fields (drug name, strength, dose form, quantity, days supply, directions, dispense unit, route, prescription date) extracted and sent to a PA endpoint.

The branches are templates, not a fixed feature set

The questionnaire titles, the gating question and answer IDs, and the medication field labels are all specific to the instance this was written for. They're constants at the top of the protocol with a comment saying so, and the README is explicit that they must be replaced. The point of the plugin is the pattern: match on a questionnaire, pull the answers you care about, forward them. It repurposes to capture any specific answers from any questionnaire in the Canvas UI.

Why

Questionnaires are where a lot of structured clinical and administrative data actually gets captured, but it lands inside a note and any system that needs to act on it has to go looking.

Prior authorization is the clearest case: drug, strength, quantity, and directions are typed into a questionnaire, then re-keyed by hand into a payer portal. Same for billing-relevant encounter flags, which sit in a note until a report picks them up later. This gets the answers to an external system at commit time, keyed by note and patient id so the rest can be pulled from the Canvas FHIR API.

Implementation notes

  • CCM_WEBHOOK_URL and PA_WEBHOOK_URL are plugin secrets, with an optional shared AUTH_TOKEN bearer — following the convention in task_webhook_notification.
  • The branches are independent. A branch whose URL secret is unset logs an error and skips its request, so an instance can run only the branch it needs by setting only that secret.
  • Questionnaires matching neither branch return early, so the plugin is inert for everything else.
  • Malformed context (missing note, patient, or extra.questions) yields null in the payload rather than raising.
  • A non-2xx response is logged as an error; there is no retry. The README notes that endpoints needing delivery guarantees should enqueue and acknowledge quickly.
  • The protocol returns no effects — it does not modify anything in Canvas.

Structure

Follows the billing-dashboard layout: README.md, LICENSE (MIT), pyproject.toml, a questionnaire_webhook/ code folder with CANVAS_MANIFEST.json inside it, and tests/.

Tests

17 tests covering both branches, routing between them, payload shape, label-driven extraction (including empty options → null), secret handling, and malformed-context cases.

uv run pytest tests/

Same caveat I noted on #412: I could not install canvas_sdk in my dev environment, so these run against stub modules. The branching logic and test wiring are exercised, but a run against the actual SDK would be a useful check.

🤖 Generated with Claude Code

On questionnaire commit, extracts specific answers and POSTs them to an
external endpoint. Ships with two example branches drawn from a real
deployment: CCM-eligible encounter flagging, and prior-authorization
medication field extraction.

The questionnaire titles, the gating question/answer IDs, and the
medication field labels are all instance-specific. They are constants at
the top of the protocol with a comment explaining they must be replaced,
and the README documents repurposing the same pattern to capture any
answers from any questionnaire.

Webhook URLs and an optional bearer token are read from plugin secrets
(CCM_WEBHOOK_URL, PA_WEBHOOK_URL, AUTH_TOKEN), following the convention
used by task_webhook_notification. Each branch is independent: a branch
whose URL is unset logs an error and skips its request.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hardylt

hardylt commented Jul 20, 2026

Copy link
Copy Markdown
Author

@JessicaHerbert

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant