awell-health / awell-extensions Goto Github PK
View Code? Open in Web Editor NEWOrchestrate actions in homegrown and third-party apps in minutes
Home Page: https://developers.awellhealth.com/awell-extensions
Orchestrate actions in homegrown and third-party apps in minutes
Home Page: https://developers.awellhealth.com/awell-extensions
There's a local/UTC mismatch somewhere in this stringDate
function (assuming it's in the parseISO function, but unsure)
import { stringDate } from '../../validation/generic.zod'
import { z } from 'zod'
describe('formatISO', () => {
test('test formatISO date', async () => {
const date = '2023-01-01'
const zodDate = z.object({ date: stringDate })
const parsed = zodDate.parse({ date })
expect(parsed).toStrictEqual({ date })
})
})
returns
$ yarn test -o
FAIL extensions/healthie/actions/__tests__/zod.ts
formatISO
✕ test formatISO date (5 ms)
● formatISO › test formatISO date
expect(received).toStrictEqual(expected) // deep equality
- Expected - 1
+ Received + 1
Object {
- "date": "2023-01-01",
+ "date": "2022-12-31",
}
7 | const zodDate = z.object({ date: stringDate })
8 | const parsed = zodDate.parse({ date })
> 9 | expect(parsed).toStrictEqual({ date })
| ^
10 | })
11 | })
12 |
at Object.<anonymous> (extensions/healthie/actions/__tests__/zod.ts:9:20)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 3.7 s, estimated 4 s
One of our customers reported a few issues in trying out the healthie extension.
- Multiple Patients -- 2 or even 4 of them -- are being created in Awell for every 1 Patient I create in Healthie.
- I can't seem to get the first step in the Care Flow, where we try to make the call back to Healthie to get the Patient's details, to work. The call does seem to be happening, according to the Activity Feed at https://care.sandbox.awellhealth.com/pathway/Rywt7IffRLxO/activity-feed, but no Data Points seem to be getting created as a result, and the Patient's Profile remains completely blank. I believe the initial webhook call from Healthie passes a "resource_id" (according to https://docs.gethealthie.com/docs/#webhooks), and I was expecting that ID to end up as the Patient Code in Awell, so that it could be used in subsequent API calls back to Healthie. But I'm probably missing a link somewhere. Can you take a look?
Also see #47 where we originally implemented reminders.
When we added the ability to configure reminders with the "Create task" action a couple of new action fields were added like:
reminderIntervalType
(string)reminderIntervalValue
(string)reminderIntervalValue
is an action field of value type string
but the problem is that depending on the value of thereminderIntervalType
action field it should either be a string or a date.
When
reminderIntervalType
type is set to "daily", leavereminderIntervalValue
blank. For "weekly" interval, send in comma separated all lower-case days of the week (e.g wednesday, friday). For "once", send in the date in ISO8601 format (e.g 2020-11-28).
So when reminderIntervalType
equals "weekly", then reminderIntervalValue
should be a comma-separated string of all lower-case days of the week. If it equals once
, then reminderIntervalValue
should be a date.
There are a couple of limitations we have to work with:
reminderIntervalValue
cannot be a string and a date at the same time)I would propose the following change but suggestions are welcome as well:
reminderIntervalType
(string) - stays as is to prevent breaking changesreminderIntervalValue
(string) - stays as is to prevent breaking changesreminderIntervalValueOnce
which has a value type of date
Set the following descriptions for the action fields:
reminderIntervalValue
: When the interval type is set to "daily" or "once", leave this field blank. For "weekly" interval, send in comma separated all lower-case days of the week (e.g wednesday, friday).reminderIntervalValueOnce
: When the interval type is set to "daily" or "weekly", leave this field blank. For "once" interval, set or select a date.Make sure that technically we grab the right value to send to the API. If reminderIntervalValue
equals weekly
, then use the value of reminderIntervalValue
(this should also be the default to avoid breaking changes). If reminderIntervalValue
equals once
, then use the value of reminderIntervalValueOnce
.
From SyncLinear.com | EXT-6
Right now there is only a single test for the canvas medical extension actions.
Each action should have its own tests. We can mock the api client. No need to test that separately (there should be unit tests in extensions-core
that cover the client.
In the first stage of our integration, we will be using Sendbird Desk to manage chats between patients and the care team. It allows the care team to have a good UX while chatting with the patient, and it allows the patient to have a seamless mobile chat experience within the app.
To register a patient into Sendbird we need to follow these steps :
Once the patient is registered in Sendbird we need to keep it up to date by updating it.
We also need to monitor the conversation, so we can trigger actions based on what happens to the ticket or within the chat.
⚠ Using Sendbird Desk require a second authentication mechanism compared to basic chat.
Uses the Chat API.
Actions fields:
Data points:
The API will return a user resource and we want to store the following fields in data points
Uses the Chat API.
Actions fields:
Data points:
The API will return a user resource and we want to store the following fields in data points
Uses the Chat API.
Actions fields:
Data points:
None
Uses the Chat API.
Actions fields:
Data points:
None
Uses the Chat API.
Actions fields:
Data points:
None
Uses the Chat API.
Actions fields:
Data points:
None
Uses the Desk API.
Action fields:
Data points:
The API will return a customer resource.
Uses the Desk API.
Action fields:
Data points:
The API will return a customer resource.
Uses the Desk API.
Action fields:
Data points:
None
Uses the Desk API.
Action fields:
Skip for now, first focus on the actions
For @michal-grzelak :-)
This action uses the updatePatient
mutation from Healthie but only assigns or removes a user_group_id
from a user.
Assign or remove a patient from a group in Healthie.
None
See submitted ticket with cal.com
If there is information in the eventType
object, perhaps there may be other information in there.
Needs some research, but despite this issue, the widget still works and a careflow with a cal.com scheduling action can still be completed successfully
We'll want to include this for client creds oauth2.0
Companies like zus and auth0 will also require it.
@radoslawstepinski if you can own, that'd be great!
Zus is known for having a "Zus Aggregated Profile" (ZAP), that contains patient information pulled (and de-duplicated) from many sources. What Zus does that is somewhat powerful is grab all of the "relevant" information, consolidate into the ZAP, and then exposes event subscriptions to customers so they can listen to ADT feeds or their corresponding FHIR Resources.
We want a very simple POC with Zus: Subscribe to the Encounter FHIR resource and allow that to trigger a careflow. A simple example could be:
This trigger could be from an admittance or from a discharge (imagine i'm a V1C--or any care provider--and one of my patients is discharged from the hospital... knowing the discharge would help me to check in with the patient and help to deliver optimal care)
The two webhooks we'll want to subscribe to are the discharge and the admittance. Both should be an Encounter resource.
They have a Postman collection that can be forked, so that might make testing out various calls quite easy, but I'm not sure what they have to test webhooks.
The "from" number is a good default "from" number, but there should also be a "From" field (Fieldtype.PHONE
) that overrides the value in "from" settings for those folks who want to send messages from different phone numbers.
Functional requirements:
Care provider ABC Health has 30 physician groups, each with its own phone number for texts and calls. Based on the physician group the patient is a part of, ABC Health needs to be able to send messages to the patient from the phone number associated with that physician group.
No - because the new action field will be made optional.
Let's do some discovery on supporting actions as classes to support a more familiar API pattern around dependency injection (i.e. decorators).
Extend the Healthie custom action Send Form Completion Request to include the following additional input fields supported by the underlying mutation:
Field to add | Description |
---|---|
is_recurring | optional. Set to true if the Form completion should be recurring. |
frequency | required if is_recurring is set to true. Valid options are: Daily, Weekly, Monthly |
period | AM or PM. |
minute | for instance, if you want to trigger the completion request at 1:05 PM, use "5". |
hour | for instance, if you want to trigger the completion request at 1:05 PM, use "1". |
weekday | use the full weekday name, e.g. "Monday". |
monthday | number of the day of month, e.g. "27th". |
recurrence_ends | set to true if the recurrence should have an end date. |
ends_on | recurrence end date in the YYYY-MM-DD format. |
The list can be found here: https://docs.gethealthie.com/docs/#creating-a-form-completion-request
From SyncLinear.com | EXT-16
//EDIT NICK: see scope in my comment 👇
My understanding from this link is that Twilio supports sending messages from a phone number or from a messagingServiceSid
(and potentially ALSO
a phone number, which must be assigned to that messaging service id)
Twilio posted information about 10DLC here, so it's going to require some understanding of requirements from @nckhell before we convert into a todo for engineers.
we either need to create a new action that supports the messaging service SID, or we need to add an optional field in our current action. Needs further discovery
From SyncLinear.com | EXT-1
the patient
field and datapoint is shown as patientId
and shows up as both string and numeric.
I'm actually kind of indifferent to numeric or string. i've used string in the past because i don't see a reason to use any of numeric's functionality (e.g. >
or <
) and working with string that look like numbers can bite, but i absolutely understand and appreciate using numeric for fields we expect to be numbers. Either way, it should be consistent. 👍
https://sendbird.com/docs/desk/platform-api/v1/features/ticket#2-create-a-ticket
🚲 Created from Cycle doc: AWE-289
Three new webhook events have to be added: goal.created
, goal.updated
, and goal.deleted
. Add/configure them in the same fashion as the other Healthie webhooks.
🚲 Created from Cycle doc: AWE-264
https://www.loom.com/share/930a9f3cfe884abbba0fe634bcf63d17
When a "Book appointment" action is activated for a given stakeholder, Awell Hosted Pages shows the booking widget when a visitor is the assigned stakeholder.
Seems reasonable that the issue reported by @bejoinka (#23) has the same root cause, at least the outcome of the bug is identical.
https://docs.gethealthie.com/docs/#updating-a-task
Call updateTask
mutation with the specified task ID and complete
set to true.
We have custom actions in our Healthie extension that perform a mutation in Healthie (create a resource, edit/update a resource, or delete a resource). Currently, we assess the success of those mutations based on the HTTP status code we receive in the response. I.e. if it’s a 200, we consider the mutation successful (eg: the task has been created) - if not, then we consider that the action failed and we call the onError
function.
However, Healthie is a GraphQL API and as many GraphQL APIs do they can return a 200 OK response even when there’s an error with the mutation.
200 OK
This status code indicates that the request was successful and that the server is returning data. However, a GraphQL API can also return a 200 OK in cases where the request contains an error, such as an invalid object name or field, or when a record is not found.
The Healthie API returns an HTTP 200 status code but the task was actually not created because the user associated with the API key doesn’t have permission to do so. Because we receive a 200 status, we do call the onComplete
function, and the action is incorrectly marked as successfully completed.
What the user sees (success while it's not):
Go over all actions in Healthie that interact with the Healthie API through a mutation (creating, updating, or deleting a resource) and assess how and if we can check that action was really successful (eg: was the task really deleted? the patient really created?).
Try to capture the error message from the Healthie API and return it with the onError
function so the reason of failure is also communicated to the end user. Eg: in the example above You do not have permission to create this task
.
Store the following data points (key
: path_to_value
)
booking.eventTypeId
booking.title
booking.descrtiopn
booking.startTime
booking.endTime
booking.status
(note to everyone... if you write a description and convert to an issue before you save your description, you lose your description)
It's difficult to find the primaryPhysicianId
and caregiverPracticeId
fields, which are necessary for various actions
Find Physicians action
Leverage the elation api documentation for the uri
Given the ability to add the Find Physicians action to the step
When I add the Find Physicians action
All three query parameters are available as fields (strings are fine, even though the npi number is technically a number)
Given i run the Find Physicians action
When the number of responses != 1
Then provide an error with a message such as "Find Physicians returned {x} results, but the number of results must equal exactly 1."
Given i run the find physicians action
When the number of responses == 1
Then add the following datapoints in onComplete (assuming the result is saved as result
):
physicianId: result.id,
physicianFirstName: result.first_name,
physicianLastName: result.last_name,
physicianCredentials: result.credentials,
physician.email: result.email,
physicianNPI: result.npi,
physicianUserId: result.user_id
caregiverPracticeId: result.practice
Please make sure the physicianId is congruent with primaryPhysicianId (primary_physician_id
) as it shows up in fields in other places in elation. Do the same with the caregiver_practice_id
.
(fyi the physicianUserId
datapoint can be used as the "author" field for the chart note)
Thanks!
🚲 Created from Cycle doc: AWE-236
The "Get patient" action ingests new data points in a care flow, one of those is the phoneNumber
data point which is typed as a string.
const dataPoints = {
...,
phoneNumber: {
key: 'phoneNumber',
valueType: 'string',
}
} satisfies Record<string, DataPointDefinition>
Although phone numbers are indeed strings, we have an even more restrictive data point type in our system for phone strings. This data point type only allows for storing valid E.164 phone strings which is useful for any downstream action you want to perform with the phone number as you can be sure the string stored in a phone data point is a semantically correct phone number according to the E.164 format.
const dataPoints = {
...,
phoneNumber: {
key: 'phoneNumber',
valueType: 'telephone',
}
} satisfies Record<string, DataPointDefinition>
Store the string we receive from Healthie in a phone data point. Given that we do not know that the string we are receiving from Healthie is in fact an E.164 valid phone string, we will have to apply some validation on our side to check whether the string we receive is a valid E.164 string or we try to parse it to one. This validation logic (validating incoming string to be a phone number) will come in handy for other actions as well, so I would create something in the /lib
folder for that. Also see what is already in lib/shared/validation
.
If the validation fails, I would store nothing (or undefined
) in the phone data point and log an event for it:
await onComplete({
data_points: {
phoneNumber: undefined
},
events: [
{
date: new Date().toISOString(),
text: { en: 'XYZ' },
error: {
category: 'XYZ',
message: "Phone number from Healthie not stored because it isn't a valid E.164 phone number",
},
},
],
})
Extensions don't support ingesting data points with the type phone
yet:
export interface DataPointDefinition {
key: string
valueType: 'string' | 'number' | 'date' // add "| 'telephone'"
}
Cal.com allows for canceling or rescheduling of already made appointments. They do that by sending a confirmation email of the appointment, and in that email, there's a link to reschedule/cancel the appointment. However, we have a customer (Better Health) who would like to take control over the notifications sent to their patients and therefore would like to disable all communication that Cal.com sends (like the confirmation email).
It would be neat I suppose if we could grab the cancel/reschedule links for use within our Email/SMS templates, which would allow us to move away from Cal.com notifications altogether, which would make for a more uniform experience.
Return the reschedule/cancel URL of the appointment as a string
data point which in itself is a fairly trivial effort. But there's some discovery needed to see whether this is actually possible.
It's currently not clear whether Cal.com returns the rescheduling/cancel URL via their API and if not, whether there is another way we can (manually) compose that URL based on other parameters. Eg: if the cancel URL is always https://cal.com/cancel/{bookingId}
then we can easily compose it by using the bookingId
. So this part needs tech discovery.
If the discovery yields the result that we cannot retrieve or compose the cancel URL ourselves, then obviously we cannot solve the problem at hand for now.
It should be the "Get booking" action that returns the URL, not the "Book appointment" action.
These extensions allow users in hosted pages to upload a file to a cloud resource / bucket. The uri and other information about the upload should be passed as data points once the upload is complete.
Nick began work on the Cloudinary extension, which supports file uploads. However, after some time this weekend, it wasn't immediately clear what was going on. There is already already some work in awell-extensions to handle, but we're going to need to do some work in hosted pages to support
Currently, the extension has some code here to support the extension vis-a-vis settings, but it's going to take some work in hosted pages to complete.
The extension has already been merged into main in order to support testing in hosted pages.
Could we timebox an effort here to try to get something up and running? How is one day?
There are still a couple leftover field and data point types that are incorrect or missing:
createTask
has a dueDate
fieldupdatePatient
now supports some of these skipped / commented out fieldsWe want to add some additional action fields to the "Create task" action. Work on this action is blocked until an extension developer can use boolean action fields (https://awellhealth.atlassian.net/browse/AST-5024).
Note, if you look at the schema you will see that some fields re conditional based on f.e. the interval type. It's not possible yet to show/hide action fields conditionally which means we will have to add descriptions to guide the user in what to configure and what not. Additionally, the code in onActivityCreated
should be smart enough to only send the relevant values, even if a user entered more values.
false
, don't pass in the reminder
object as input to the GraphQL mutation.daily
then reminderIntervalValue should be null (no validation needed, just omit it from the input)weekly
then reminderIntervalValue should be a comma-separated string with only these possible values: monday
, tuesday
, wednesay
, thursday,
friday,
saturday,
sunday`. If not, return a clear error.once
then reminderIntervalValue should be an ISO8601 string. If not, return a clear error.The "Get patient" action ingests new data points in a care flow, one of those is the dob
data point which is typed as a string.
const dataPoints = {
...,
dob: {
key: 'dob',
valueType: 'string',
},
} satisfies Record<string, DataPointDefinition>
const dataPoints = {
...,
dob: {
key: 'dob',
valueType: 'date', // should be ISO8601 date string
},
} satisfies Record<string, DataPointDefinition>
Store the dob string we receive from Healthie in a date data point. We might need to try and parse the incoming string value from Healthie to a data and then use date-fns
to parse it to ISO8601 string date.
Pseudocode
import { isValid, formatISO } from 'date-fns'
const getDateValue = (incoming_dob: string) => {
const date = new Date(incoming_dob)
const isValidDate = isValid(date)
if (isValidDate) return formatISO(date)
return undefined
}
Canvas Medical is another EHR. It is one of our goals to have five EHR integrations this quarter, and Canvas will be number 3!
Canvas' FHIR API adheres to the FHIR R4 specification (read more here). FHIR is becoming industry-standard so capturing these resources and mapping them to Awell will be useful beyond just Canvas' integration.
They have a nice postman collection, ready to be forked. Should make testing the API fairly simple. They also have an SDK. Again, seems like it has the opportunity to be pretty straightforward.
Original scope from V1C-52:
v1 Beta Scope:
From SyncLinear.com | EXT-7
cm.com is a communications Platform for Messaging & Voice and is in that perspective very similar to our Twilio extension. Heilig-Hart Lier (Belgium hospital) uses cm.com as their notification provider.
Please have a look at https://developers.cm.com/messaging/docs/sms and https://developers.cm.com/messaging/reference/messages_sendmessage-1
You can ask Nick for an invite to cm.com. We have an Awell Health account there which allows you to get test credentials and allows you to actually test the sending of text messages.
Minimally required:
{
"messages": {
"authentication": {
"productToken": "{{productToken}}"
},
"msg": [
{
"from": "{{fromName}}",
"body": {
"type": "auto",
"content": "{{message}}",
},
"reference": "{{AWELL_ACTIVITY_ID}}",
"to": [
{
"number": "{{recipient}}"
}
],
"allowedChannels": [
"SMS"
],
"minimumNumberOfMessageParts": 1,
"maximumNumberOfMessageParts": 8,
}
]
}
Why set maximumNumberOfMessageParts to 8?
The SMS standard theoretically permits up to 255 message parts (which could mean you would send messages of 153 times 255 = 39.000 characters). In practice you should try to limit your message to 8 message parts – thus 153 times 8 = 1.224 characters or 67 times 8 == 536 for unicode messages.
Why set allowedChannels to SMS only?
We want this action to only communicate over SMS, even if there are any other channels configured in cm.com.
We would like to add support for the DrChrono EHR through a new extension.
The API docs can be found here.
The scope for this new action is not determined yet, so the recommendation is to start with a set of standard actions in the EHR integration category (create / update / get patient, create / get clinical note).
Note that this API uses a new authentication scheme that is not fully supported yet (Authorization Grant flow). At this time we have not decided how the initial authorization flow will be handled, so this should be excluded from the scope of this task. Instead you should assume that an authorization token is available in the token service and use that to authorize all API calls.
Given that the functional scope for this extension has not been internally shaped yet, the first tasks are:
For internal reference:
https://awellhealth.atlassian.net/browse/AST-5057
Healthie-SendChatMessage should strip <span>
tags before sending because we wrap our variables in <span>
tags and they are inappropriately handled by anchorme.
This issue is blocking work from one of our customers who uses healthie to send dynamic links through Healthie.
When sending a chat to healthie, tags are parsed incorrectly.
Learned from Healthie they use anchorme, and it appears they may not have the appetite to solve it, so here's what we can do on our end:
import { load as cheerioLoad } from 'cheerio';
import anchorme from 'anchorme';
const htmlContent = '<p class="slate-p">https://securestaging.gethealthie.com/appointments/embed_appt?dietitian_id=52848&provider_ids=[<span>52848</span>]&appt_type_ids=[19420]&org_level=true</p>';
// Parse the HTML content using cheerio
const $ = cheerioLoad(htmlContent);
// Remove all <span> tags
$('span').replaceWith(function () {
return $(this).contents();
});
// Get the modified HTML content
const modifiedHtmlContent = $.html();
// Pass the modified content to Anchorme for URL parsing
const parsedUrls = anchorme(modifiedHtmlContent);
// Unparsed content, for comparison
const unparsedContent = anchorme(htmlContent);
// Output the parsed URLs
console.log('unparsed:\n', unparsedContent, '\nparsed:\n', parsedUrls);
Output:
unparsed:
<p class="slate-p"><a href="https://securestaging.gethealthie.com/appointments/embed_appt?dietitian_id=52848&provider_ids=">https://securestaging.gethealthie.com/appointments/embed_appt?dietitian_id=52848&provider_ids=</a>[<span>52848</span>]&appt_type_ids=[19420]&org_level=true</p>
parsed:
<html><head></head><body><p class="slate-p"><a href="https://securestaging.gethealthie.com/appointments/embed_appt?dietitian_id=52848&provider_ids=[52848]&appt_type_ids=[19420]&org_level=true">https://securestaging.gethealthie.com/appointments/embed_appt?dietitian_id=52848&provider_ids=[52848]&appt_type_ids=[19420]&org_level=true</a></p></body></html>
We have a customer that uses Sendgrid and we therefore want to have a Sendgrid extension.
Why create the extension now?
Wellinks needs an additional action for Sendgrid and we don't want to build that into the legacy plugin anymore. So seems like the right thing to do is to create the extension now and add the additional actions immediately.
I am gonna keep this short as I believe there are sufficient references of extensions that integrate with other email providers (see Mailgun and Mailchimp extension) and Sendgrid has good documentation.
But, what's minimally needed:
See https://docs.sendgrid.com/api-reference/contacts/add-or-update-a-contact
Functional requirements:
202
status code then you can mark the action as completed.Please make sure that relevant information from the Sendgrid docs make it into the README. Eg: Please note that custom fields need to have been already created if you wish to set their values for the contacts being upserted. To do this, please use the "Create Custom Field Definition" endpoint.
AND The contact to update will be determined only by the email field and any fields omitted from the request will remain as they were. A contact's ID cannot be used to update the contact.
.
https://docs.gethealthie.com/docs/#deleting-a-task
Task ID
Call deleteTask
mutation with the specified task ID.
nickname
is currently a required action field (because it's required for making the API call to Sendbird) but we want to make it optional and set a sensible default.
nickname
becomes optionalnickname
to {patientFirstName} {patientLastName}
(both available in payload.patient
.firstName
and the lastName
of the patient are not known in Awell and nickname
action field is not specified either, then we should throw an error. I.e. we should never allow calling the Sendbird API when nickname
has no valueThe user's nickname. Maximum length is 80 characters. If left empty, we will use the patient's first and last name.
We would like to create a new extension for signing documents through DocuSign.
The existing DropboxSign extension can be used as a reference for the functional scope of this new extension.
High level, the expected outcome is that this extension allows any care flow stakeholder to sign a document from within a hosted page session.
Given that this has not been internally shaped yet, the first task is to look at the developer docs and determine:
Currently, all requests made to an OAuth provider also always make a request to the authentication server to get a new token. While this functionality was acceptable for our POC, it's not okay in production and we need to improve upon it by leveraging a cache of some sort.
The request flow should be something like this:
"expires_in"
for future token validation)There is already a retry mechanism in the API Client, but it's missing all of the appropriate token service functionality.
Eventually, we're going to want to use a shared cache (e.g. redis). Feel free to build this service as though there was a redis service in place:
HSET
HGET(ALL)
If someone is testing locally, though, we'd want to support an in-memory cache.
A: I think a sufficient hash for the key would be a hash from the OAuth object... what do you think?
A: I'm open to however you want to determine that at runtime
A: I'm open to suggestions here as well!
@ebomcke-awell feel free to comment!
We want to add support for Webhooks to the Cal.com extension
https://cal.com/docs/core-features/webhooks
Add it right below "Custom Actions"
## Webhooks
Webhooks offer a great way to automate the flow with Awell when invitees schedule, cancel, or reschedule events, or when the meeting ends.
**Important notes:**
1. An Awell webhook endpoint can only listen to one event type. So make sure that when you create a webhook in Cal.com, the subscriber URL and the event trigger match the Awell webhook endpoint. This also means there can only be one event type per subscriber URL.
2. Using a secret to verify the authenticity of the received payload is not yet supported.
3. Custom payload templates are not supported, please use the default ones.
See https://github.com/awell-health/awell-extensions/tree/main/extensions/healthie/webhooks for reference.
There's an example payload of the booking.created
event available on their docs.
Store the bookingId
and the bookingUid
in a data point.
Unfortunately, there is no example payload of this event type available on their docs but I assume we can also store the bookingId
and the bookingUid
in a data point.
Unfortunately, there is no example payload of this event type available on their docs but I assume we can also store the bookingId
and the bookingUid
in a data point.
There's a bunch of if err instanceof ZodError
, if err instanceof AxiosError
, and catch-all error boilerplate all over the place.
Let's remove it and push those handlers to the awell-extension-server
, and clean up some of these actions.
This activity will need to be completed after this issue from awell-extension-server. Please refer to the Should Have / Could Have in that referenced issue.
After an issue related to onComplete()
being called twice in an extension action, it seems as though we can do a better job guiding developers by providing stronger guardrails in our API.
For example, tests should use ToHaveBeenCalledTimes(1)
instead of ToHaveBeenCalled()
when checking for OnComplete
or OnError
to have been called.
In addition, we could potentially use code coverage to help us to spot gaps in extension tests.
Just like the Cloudinary extension, users may want to use an S3 bucket for a file upload.
Building a POC here should be timeboxed to a day as well. Given there is the potential to duplicate code from cloudinary, most of the work is likely in the hosted pages repo.
Currently, this issue is standing in as a placeholder until more details are fleshed out, including what the hosted page will look like for the upload.
Update after feedback from a customer.
In all three actions of the extension where we have an email
type action field, the type of the action field should be just string (so remove the stringType
email). This is due to a limitation on our side which I forgot when scoping the initiative.
For internal reference: https://awellhealth.atlassian.net/jira/polaris/projects/AH/ideas/view/548618?selectedIssue=AH-176&issueViewLayout=sidebar&issueViewSection=capture&focusedInsightId=3144292
https://docs.sendgrid.com/api-reference/contacts/add-or-update-a-contact
Add the following action fields after email
and make sure they are passed with the request
Should be From label
for the label and not fromLabel
.
The non-visit note is a special kind of note that, as the name suggests, is not associated with a visit. These notes, in their simplest form, provide a chronological account of information about the patient. While they can be plain text, they can also contain vitals and links to other documents.
My understanding is that non-visit notes are the most appropriate format for this sort of information.
In terms of how we want to handle, the goal here will be to not mutate the required object, but instead omit items we can't support. So, we'll support tags
as an array of ints. we won't support note_documents
or note_items
yet.
The one exception is going to be bullets
. We're going to have to support that, because that's where the note is. Here, we'll just support a single note:
physicianUserId
(see #107 )Normally, the note is used for historical documents from other doctors. "Hey, you've got your old charts? we'll log them as non-visit notes, add them as documents, and include bullets to summarize the documents."-
That's the normal use case ☝️ ... but, we're going to be using these as a way to log inputs from forms.
If we get feedback from customers that the non-visit note is not the best way to use these notes, we'll make adjustments and perhaps add some other way to perform this use case... but that's where we're starting for now.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.