@everfur/sdk 0.1.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/CHANGELOG.md +703 -4
  2. package/README.md +63 -23
  3. package/consent/package.json +8 -0
  4. package/dist/Chat-BZZ-Py5l.d.ts +128 -0
  5. package/dist/Chat-Dq4fffIO.d.cts +128 -0
  6. package/dist/DepthViews-BG3E25MD.d.ts +16 -0
  7. package/dist/DepthViews-B_hIypI6.d.cts +19 -0
  8. package/dist/DepthViews-CL75jyRA.d.cts +16 -0
  9. package/dist/DepthViews-CkYri51q.d.ts +19 -0
  10. package/dist/ErrorPolicyPort-CNf4uQZP.d.cts +22 -0
  11. package/dist/ErrorPolicyPort-CwbfmxzJ.d.ts +22 -0
  12. package/dist/{EverfurResult-D92-uL82.d.cts → EverfurResult-DN9pL2Ab.d.cts} +11 -10
  13. package/dist/{EverfurResult-D92-uL82.d.ts → EverfurResult-DN9pL2Ab.d.ts} +11 -10
  14. package/dist/{PhotoController-BItt5M7u.d.cts → PhotoController-3l7MT9jA.d.cts} +1 -1
  15. package/dist/{PhotoController-D8zMTdcW.d.ts → PhotoController-vzY5bfY_.d.ts} +1 -1
  16. package/dist/animations/index.cjs +1 -1997
  17. package/dist/animations/index.d.cts +35 -35
  18. package/dist/animations/index.d.ts +35 -35
  19. package/dist/animations/index.js +1 -1972
  20. package/dist/attachments-BorG422I.d.cts +146 -0
  21. package/dist/attachments-BrUWQYNK.d.ts +257 -0
  22. package/dist/attachments-D_SECjr1.d.cts +257 -0
  23. package/dist/attachments-DpldrvIW.d.ts +146 -0
  24. package/dist/bookingCopy-CqtDYvCR.d.ts +732 -0
  25. package/dist/bookingCopy-SREvkG19.d.cts +732 -0
  26. package/dist/branding-CsRdeNwK.d.cts +566 -0
  27. package/dist/branding-CsRdeNwK.d.ts +566 -0
  28. package/dist/callCopy-DoQKG3-L.d.cts +40 -0
  29. package/dist/callCopy-DoQKG3-L.d.ts +40 -0
  30. package/dist/casesRepository-DwtZVsbj.d.cts +51 -0
  31. package/dist/casesRepository-v6QczS9N.d.ts +51 -0
  32. package/dist/chat/index.cjs +1 -1170
  33. package/dist/chat/index.d.cts +32 -53
  34. package/dist/chat/index.d.ts +32 -53
  35. package/dist/chat/index.js +1 -1167
  36. package/dist/client/index.cjs +9 -2315
  37. package/dist/client/index.d.cts +80 -16
  38. package/dist/client/index.d.ts +80 -16
  39. package/dist/client/index.js +9 -2215
  40. package/dist/{config-CiJ0PVBB.d.ts → config--Wu1Umhd.d.cts} +64 -26
  41. package/dist/{config-BSjBdxrZ.d.cts → config-C7eb_IMD.d.ts} +64 -26
  42. package/dist/consent/index.cjs +1 -0
  43. package/dist/consent/index.d.cts +33 -0
  44. package/dist/consent/index.d.ts +33 -0
  45. package/dist/consent/index.js +1 -0
  46. package/dist/context-CL3lyuy1.d.cts +159 -0
  47. package/dist/context-CahAEha8.d.ts +159 -0
  48. package/dist/copy-DdVFDL01.d.ts +198 -0
  49. package/dist/copy-UeUJVk8X.d.cts +198 -0
  50. package/dist/core/index.cjs +13 -3178
  51. package/dist/core/index.d.cts +164 -29
  52. package/dist/core/index.d.ts +164 -29
  53. package/dist/core/index.js +13 -3166
  54. package/dist/depth-D5HwcvKC.d.cts +533 -0
  55. package/dist/depth-DvPwPuT_.d.ts +533 -0
  56. package/dist/entitlementRepository-B7egEdW6.d.ts +43 -0
  57. package/dist/entitlementRepository-BpJ7tiwl.d.cts +43 -0
  58. package/dist/{identity-Brl-lDd6.d.cts → identity-C2-08BZW.d.cts} +20 -7
  59. package/dist/{identity-DK9zORrG.d.ts → identity-CEi9GRFZ.d.ts} +20 -7
  60. package/dist/{ids-CJ1S6adf.d.cts → ids-B2GAAifq.d.cts} +1 -1
  61. package/dist/{ids-CJ1S6adf.d.ts → ids-B2GAAifq.d.ts} +1 -1
  62. package/dist/index.cjs +12 -4494
  63. package/dist/index.d.cts +30 -121
  64. package/dist/index.d.ts +30 -121
  65. package/dist/index.js +12 -4470
  66. package/dist/models-B-Uh2LTf.d.ts +214 -0
  67. package/dist/models-D2EUxPZY.d.cts +214 -0
  68. package/dist/notifications/index.cjs +2 -0
  69. package/dist/notifications/index.d.cts +17 -0
  70. package/dist/notifications/index.d.ts +17 -0
  71. package/dist/notifications/index.js +2 -0
  72. package/dist/optionalModule-DbJmsq5f.d.cts +21 -0
  73. package/dist/optionalModule-DbJmsq5f.d.ts +21 -0
  74. package/dist/pets-DJv2sj2H.d.ts +92 -0
  75. package/dist/pets-JVCXgRgR.d.cts +92 -0
  76. package/dist/petsRepository-B_gKbAzJ.d.cts +142 -0
  77. package/dist/petsRepository-Bk6GDwLs.d.ts +142 -0
  78. package/dist/photo/index.cjs +1 -2189
  79. package/dist/photo/index.d.cts +6 -6
  80. package/dist/photo/index.d.ts +6 -6
  81. package/dist/photo/index.js +1 -2186
  82. package/dist/ports-BN6RHF9W.d.cts +48 -0
  83. package/dist/ports-BN6RHF9W.d.ts +48 -0
  84. package/dist/ports-BY2ph0_y.d.cts +376 -0
  85. package/dist/ports-D7YW8qz9.d.ts +376 -0
  86. package/dist/profile-CSs1wlXT.d.cts +93 -0
  87. package/dist/profile-CSs1wlXT.d.ts +93 -0
  88. package/dist/records/depth/index.cjs +2 -0
  89. package/dist/records/depth/index.d.cts +13 -0
  90. package/dist/records/depth/index.d.ts +13 -0
  91. package/dist/records/depth/index.js +2 -0
  92. package/dist/records/index.cjs +3 -2839
  93. package/dist/records/index.d.cts +137 -203
  94. package/dist/records/index.d.ts +137 -203
  95. package/dist/records/index.js +3 -2833
  96. package/dist/requestFunnel-BjDpqqvm.d.cts +110 -0
  97. package/dist/requestFunnel-DFMGcluw.d.ts +110 -0
  98. package/dist/{resolve-Dq_4_agU.d.ts → resolve-D4Ywz5OS.d.cts} +10 -4
  99. package/dist/{resolve-Dq_4_agU.d.cts → resolve-D4Ywz5OS.d.ts} +10 -4
  100. package/dist/{runtime-Bvr8yqXm.d.cts → runtimeTypes-gZEJu-da.d.cts} +104 -132
  101. package/dist/{runtime-BIYzf9cK.d.ts → runtimeTypes-w5KqBMcs.d.ts} +104 -132
  102. package/dist/server/events/index.cjs +2 -0
  103. package/dist/server/events/index.d.cts +550 -0
  104. package/dist/server/events/index.d.ts +550 -0
  105. package/dist/server/events/index.js +2 -0
  106. package/dist/server/index.cjs +2 -533
  107. package/dist/server/index.d.cts +73 -18
  108. package/dist/server/index.d.ts +73 -18
  109. package/dist/server/index.js +2 -530
  110. package/dist/species-BXAIMh7I.d.cts +9 -0
  111. package/dist/species-BXAIMh7I.d.ts +9 -0
  112. package/dist/televet/booking/index.cjs +1 -0
  113. package/dist/televet/booking/index.d.cts +294 -0
  114. package/dist/televet/booking/index.d.ts +294 -0
  115. package/dist/televet/booking/index.js +1 -0
  116. package/dist/televet/call/index.cjs +1 -0
  117. package/dist/televet/call/index.d.cts +141 -0
  118. package/dist/televet/call/index.d.ts +141 -0
  119. package/dist/televet/call/index.js +1 -0
  120. package/dist/televet/index.cjs +1 -0
  121. package/dist/televet/index.d.cts +142 -0
  122. package/dist/televet/index.d.ts +142 -0
  123. package/dist/televet/index.js +1 -0
  124. package/dist/testing/index.cjs +5 -823
  125. package/dist/testing/index.d.cts +18 -4
  126. package/dist/testing/index.d.ts +18 -4
  127. package/dist/testing/index.js +5 -820
  128. package/dist/testing/rn/index.cjs +1 -449
  129. package/dist/testing/rn/index.d.cts +18 -29
  130. package/dist/testing/rn/index.d.ts +18 -29
  131. package/dist/testing/rn/index.js +1 -444
  132. package/dist/testing/web/index.cjs +1 -0
  133. package/dist/testing/web/index.d.cts +132 -0
  134. package/dist/testing/web/index.d.ts +132 -0
  135. package/dist/testing/web/index.js +1 -0
  136. package/dist/timelineRows-C15jxFFH.d.ts +19 -0
  137. package/dist/timelineRows-odO8g9r2.d.cts +19 -0
  138. package/dist/typeStyle-CKqVYD6L.d.cts +111 -0
  139. package/dist/typeStyle-DmoyacDG.d.ts +111 -0
  140. package/dist/uploadTransport-D0M0T4hN.d.ts +38 -0
  141. package/dist/uploadTransport-DKJHs3Yj.d.cts +38 -0
  142. package/dist/useRecordsDepth-C6rjEaLn.d.cts +237 -0
  143. package/dist/useRecordsDepth-crhBllQK.d.ts +237 -0
  144. package/dist/useVetVisit-Bc84hWUU.d.cts +187 -0
  145. package/dist/useVetVisit-CjmMa896.d.ts +187 -0
  146. package/dist/video/index.cjs +1 -1941
  147. package/dist/video/index.d.cts +4 -4
  148. package/dist/video/index.d.ts +4 -4
  149. package/dist/video/index.js +1 -1938
  150. package/dist/view-Bxwxp4xD.d.ts +310 -0
  151. package/dist/view-DyitEO0m.d.cts +310 -0
  152. package/dist/visitIntent-D7_yVp1I.d.cts +8 -0
  153. package/dist/visitIntent-D7_yVp1I.d.ts +8 -0
  154. package/dist/web/consent/index.cjs +1 -0
  155. package/dist/web/consent/index.d.cts +34 -0
  156. package/dist/web/consent/index.d.ts +34 -0
  157. package/dist/web/consent/index.js +1 -0
  158. package/dist/web/index.cjs +14 -0
  159. package/dist/web/index.d.cts +218 -0
  160. package/dist/web/index.d.ts +218 -0
  161. package/dist/web/index.js +14 -0
  162. package/dist/web/notifications/index.cjs +2 -0
  163. package/dist/web/notifications/index.d.cts +213 -0
  164. package/dist/web/notifications/index.d.ts +213 -0
  165. package/dist/web/notifications/index.js +2 -0
  166. package/dist/web/records/depth/index.cjs +2 -0
  167. package/dist/web/records/depth/index.d.cts +12 -0
  168. package/dist/web/records/depth/index.d.ts +12 -0
  169. package/dist/web/records/depth/index.js +2 -0
  170. package/dist/web/records/index.cjs +4 -0
  171. package/dist/web/records/index.d.cts +285 -0
  172. package/dist/web/records/index.d.ts +285 -0
  173. package/dist/web/records/index.js +4 -0
  174. package/dist/web/televet/booking/index.cjs +1 -0
  175. package/dist/web/televet/booking/index.d.cts +349 -0
  176. package/dist/web/televet/booking/index.d.ts +349 -0
  177. package/dist/web/televet/booking/index.js +1 -0
  178. package/dist/web/televet/call/index.cjs +1 -0
  179. package/dist/web/televet/call/index.d.cts +142 -0
  180. package/dist/web/televet/call/index.d.ts +142 -0
  181. package/dist/web/televet/call/index.js +1 -0
  182. package/dist/web/televet/index.cjs +1 -0
  183. package/dist/web/televet/index.d.cts +136 -0
  184. package/dist/web/televet/index.d.ts +136 -0
  185. package/dist/web/televet/index.js +1 -0
  186. package/notifications/package.json +8 -0
  187. package/package.json +266 -10
  188. package/records/depth/package.json +8 -0
  189. package/server/events/device-blocked.cjs +15 -0
  190. package/server/events/package.json +9 -0
  191. package/televet/booking/package.json +8 -0
  192. package/televet/call/package.json +8 -0
  193. package/televet/package.json +8 -0
  194. package/testing/web/native-blocked.cjs +12 -0
  195. package/testing/web/package.json +8 -0
  196. package/web/consent/native-blocked.cjs +12 -0
  197. package/web/consent/package.json +8 -0
  198. package/web/native-blocked.cjs +12 -0
  199. package/web/notifications/native-blocked.cjs +12 -0
  200. package/web/notifications/package.json +8 -0
  201. package/web/package.json +8 -0
  202. package/web/records/depth/native-blocked.cjs +12 -0
  203. package/web/records/depth/package.json +8 -0
  204. package/web/records/native-blocked.cjs +12 -0
  205. package/web/records/package.json +8 -0
  206. package/web/televet/booking/native-blocked.cjs +12 -0
  207. package/web/televet/booking/package.json +8 -0
  208. package/web/televet/call/native-blocked.cjs +12 -0
  209. package/web/televet/call/package.json +8 -0
  210. package/web/televet/native-blocked.cjs +12 -0
  211. package/web/televet/package.json +8 -0
  212. package/dist/ChatController-CKdBvPj2.d.ts +0 -146
  213. package/dist/ChatController-CpUMvvZf.d.cts +0 -146
  214. package/dist/FilePort-BabWrv7I.d.cts +0 -22
  215. package/dist/FilePort-BabWrv7I.d.ts +0 -22
  216. package/dist/petsRepository-BEGb97M9.d.cts +0 -326
  217. package/dist/petsRepository-Bu18r2kK.d.ts +0 -326
  218. package/dist/requestFunnel-DuUH-kAe.d.cts +0 -28
  219. package/dist/requestFunnel-dio5OmR9.d.ts +0 -28
@@ -0,0 +1,550 @@
1
+ import { b as PartnerPetProfile } from '../../pets-JVCXgRgR.cjs';
2
+ import { c as EverfurResult } from '../../EverfurResult-DN9pL2Ab.cjs';
3
+ import { j as FetchLike } from '../../config--Wu1Umhd.cjs';
4
+ export { b as PetActivityLevel, c as PetAllergy, d as PetAllergySeverity, e as PetBirthDatePrecision, f as PetCondition, P as PetHealthProfileInput, g as PetIndoorOutdoor, h as PetMedication, i as PetSex } from '../../profile-CSs1wlXT.cjs';
5
+
6
+ /** Every outbound event type in the catalog. Order matches EFBackend `OUTBOUND_EVENT_TYPES`. */
7
+ declare const EVERFUR_WEBHOOK_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "visit.booked", "visit.cancelled", "visit.completed", "visit.no_show", "record_request.updated", "record.ready", "webhook_endpoint.test", "chat.follow_up_due", "chat.urgency.flagged", "pet.vaccination.due", "visit.rescheduled", "visit.reminder", "visit.followup_sent", "chat.reminder_due", "record.activation", "visit.message_received", "visit.ended"];
8
+ /** One outbound event type name. */
9
+ type EverfurWebhookEventType = (typeof EVERFUR_WEBHOOK_EVENT_TYPES)[number];
10
+ /**
11
+ * The types that reach your WEBHOOK ONLY and can never reach a member's device, whatever the member's
12
+ * notification settings say (EFBackend `partner_notifications/channels.py` NO_COPY_TYPES, which is also why
13
+ * `partner_target.py` builds no push target for them):
14
+ *
15
+ * - `member.linked` / `member.unlinked` are your bookkeeping, not news for the member;
16
+ * - `chat.urgency.flagged` is an in-app affordance, not a push;
17
+ * - `webhook_endpoint.test` is the console's own test button.
18
+ *
19
+ * Every OTHER catalog type does build a push target, so it can announce itself on a device and
20
+ * `parseEverfurNotification` can read it (three of them, `visit.completed`, `visit.rescheduled` and
21
+ * `visit.ended`, have a target but no consumer copy, so in practice no push is sent for them either).
22
+ * Read this list when you decide which events your own backend must act on rather than leave to the device.
23
+ */
24
+ declare const EVERFUR_WEBHOOK_ONLY_EVENT_TYPES: readonly ["member.linked", "member.unlinked", "chat.urgency.flagged", "webhook_endpoint.test"];
25
+ /** One type that never reaches a device. */
26
+ type EverfurWebhookOnlyEventType = (typeof EVERFUR_WEBHOOK_ONLY_EVENT_TYPES)[number];
27
+ /** Fields any payload may carry beyond the ones typed here (forward compatible). */
28
+ interface OpenEventPayload {
29
+ readonly [field: string]: unknown;
30
+ }
31
+ /** `member.linked` / `member.unlinked`: a partner member's link to an Everfur account changed. */
32
+ interface MemberLinkPayload extends OpenEventPayload {
33
+ readonly object: 'member';
34
+ /** Your own opaque id for the member, as you passed it when minting the session. */
35
+ readonly user_ref: string;
36
+ }
37
+ /**
38
+ * What the partner may know a visit to be. A visit in progress or awaiting its note is still `booked`; every
39
+ * terminal consult status maps to one of the other three (`VISIT_STATUS_BY_CONSULT_STATUS`), and a visit
40
+ * nobody attended and nobody cancelled is a `no_show` that blames no one.
41
+ */
42
+ type EverfurVisitStatus = 'booked' | 'cancelled' | 'completed' | 'no_show';
43
+ /**
44
+ * The fields every `visit.*` event carries (`VISIT_EVENT_DATA_KEYS`). Sent only for a visit that started from
45
+ * your integration, and only when the member opted in to share visit status with you.
46
+ */
47
+ interface VisitPayload extends OpenEventPayload {
48
+ readonly object: 'visit';
49
+ /**
50
+ * The visit's opaque partner reference (the platform's `partner_visit_ref`, minted when a visit starts from
51
+ * your integration). Never an internal consult id, and the same on every event for that visit; a follow-up
52
+ * visit gets its own.
53
+ */
54
+ readonly visit_ref: string;
55
+ readonly user_ref: string;
56
+ /** Your pet id, or `null` when you never named a pet for this link (or the owner has not confirmed one). */
57
+ readonly pet_ref: string | null;
58
+ /** The partner-visible status of the visit at the moment of the event. */
59
+ readonly status: EverfurVisitStatus;
60
+ /** ISO 8601. The visit's scheduled time; on `visit.rescheduled` it is already the NEW time. */
61
+ readonly scheduled_at: string;
62
+ /** ISO 8601. When the change happened (the status transition, the reschedule, the reminder or the send). */
63
+ readonly occurred_at: string;
64
+ }
65
+ /** `visit.rescheduled`: the owner moved the visit. `status` is `booked`. */
66
+ interface VisitRescheduledPayload extends VisitPayload {
67
+ readonly status: 'booked';
68
+ /** ISO 8601. The time the visit was scheduled for before this move. */
69
+ readonly previous_scheduled_at: string;
70
+ }
71
+ /** The two consumer reminder rows, by lead time (`VISIT_REMINDER_STAGE_BY_OUTBOX_EVENT`). */
72
+ type EverfurVisitReminderStage = '24h' | '30m';
73
+ /** `visit.reminder`: the member's reminder for a visit still to happen was released. `status` is `booked`. */
74
+ interface VisitReminderPayload extends VisitPayload {
75
+ readonly status: 'booked';
76
+ readonly stage: EverfurVisitReminderStage;
77
+ }
78
+ /**
79
+ * `visit.followup_sent`: the post-visit check-in message was delivered to the member. `status` is what the
80
+ * partner may know the visit to be at that moment: `completed`, or `booked` while the note is still pending.
81
+ */
82
+ interface VisitFollowupSentPayload extends VisitPayload {
83
+ readonly status: 'booked' | 'completed';
84
+ /** ISO 8601. When the check-in was sent. Never the message. */
85
+ readonly sent_at: string;
86
+ }
87
+ /**
88
+ * `visit.message_received` (owner decision 4): the vet wrote in the visit thread. One per message. Ids and one
89
+ * timestamp: never the message, a preview or the vet's name.
90
+ */
91
+ interface VisitMessageReceivedPayload extends VisitPayload {
92
+ /** ISO 8601. When the vet's message was written. */
93
+ readonly message_at: string;
94
+ }
95
+ /**
96
+ * `visit.ended` (owner decision 4): the call ended, before the note is signed, so your list can stop reading
97
+ * "booked" for a visit that has happened. One per visit. The status is still `booked` until the note is signed and
98
+ * `visit.completed` arrives.
99
+ */
100
+ interface VisitEndedPayload extends VisitPayload {
101
+ /** ISO 8601. When the call ended. */
102
+ readonly ended_at: string;
103
+ }
104
+ /** The seven simple statuses of the one records status model (`records_simple_status.SimpleStatus`). */
105
+ type RecordRequestSimpleStatus = 'requested' | 'awaiting_clinic' | 'received' | 'parsing' | 'published' | 'failed' | 'revoked';
106
+ /**
107
+ * `record_request.updated`: a records request reached a new simple state, or a reviewer amended the record after
108
+ * it was published (one more `published` event per amendment). Field set pinned by EFBackend
109
+ * `tests/records/test_records_partner_events.py`.
110
+ */
111
+ interface RecordRequestUpdatedPayload extends OpenEventPayload {
112
+ readonly object: 'record_request';
113
+ readonly request_id: string;
114
+ readonly user_ref: string;
115
+ readonly pet_ref: string;
116
+ /** The request's state in the seven-value simple status model. Never the raw status. */
117
+ readonly simple_status: RecordRequestSimpleStatus;
118
+ /**
119
+ * The partner-safe detail code, or `null` when the status says it all. The closed allowlist today is
120
+ * `awaiting_owner_upload`, `received_without_document`, `in_review`, `clinic_declined`, `no_response`,
121
+ * `hard_bounce` and `clinic_replied_without_records`; it can grow, so handle a value you do not know.
122
+ */
123
+ readonly simple_status_detail: string | null;
124
+ /** The consumer app's action-first sentence for an action-needed state, or `null`. Render verbatim. */
125
+ readonly action_needed_label: string | null;
126
+ /** The request's own recovery policy: what the member could do next, as the consumer app shows it. */
127
+ readonly can_retry_send: boolean;
128
+ readonly can_update_clinic_email: boolean;
129
+ readonly can_revoke: boolean;
130
+ readonly can_convert_to_upload: boolean;
131
+ /** ISO 8601. When the PUBLISHED record last changed (the latest amendment, else the publish); `null` before. */
132
+ readonly record_updated_at: string | null;
133
+ }
134
+ /** `record.ready`: a requested record is readable through the records API. Carries no record content. */
135
+ interface RecordReadyPayload extends OpenEventPayload {
136
+ readonly object: 'record';
137
+ readonly request_id: string;
138
+ readonly user_ref: string;
139
+ readonly pet_ref: string;
140
+ }
141
+ /** The catalog vaccines a due-date reminder names (never a product label). */
142
+ type EverfurVaccine = 'rabies' | 'dhpp';
143
+ /** The consumer reminder stages a due date reaches: 14 days out, 3 days out, then overdue. */
144
+ type EverfurVaccinationDueStage = 'due_in_14d' | 'due_in_3d' | 'overdue';
145
+ /**
146
+ * `pet.vaccination.due`: a widget pet's rabies or DHPP due date reached a reminder stage. One event per (pet,
147
+ * vaccine, due date, stage), from the same snapshot the consumer app reminds from. Ids and closed codes only.
148
+ */
149
+ interface PetVaccinationDuePayload extends OpenEventPayload {
150
+ readonly object: 'pet_vaccination';
151
+ readonly user_ref: string;
152
+ readonly pet_ref: string;
153
+ readonly vaccine: EverfurVaccine;
154
+ /** `YYYY-MM-DD`. */
155
+ readonly due_at: string;
156
+ readonly stage: EverfurVaccinationDueStage;
157
+ }
158
+ /**
159
+ * `chat.follow_up_due`: a follow-up check-in for a watched case is due. The partner's webhook replaces the
160
+ * consumer push; the in-thread check-in itself arrives through the conversation list. Ids and one timestamp,
161
+ * never the check-in sentence.
162
+ */
163
+ interface ChatFollowUpDuePayload extends OpenEventPayload {
164
+ readonly object: 'chat_follow_up';
165
+ readonly user_ref: string;
166
+ readonly pet_ref: string;
167
+ /** The opaque case id (`WatchCase.caseId`). */
168
+ readonly case_ref: string;
169
+ /** The thread the check-in lands in when one exists, else `null`. */
170
+ readonly conversation_id: string | null;
171
+ /** ISO 8601. */
172
+ readonly due_at: string;
173
+ }
174
+ /**
175
+ * `chat.urgency.flagged`: an assistant reply carried an emergency urgency verdict. One per flagged message.
176
+ * Ids plus the closed level; no reason, no text. The backend writes no `pet_ref` on this event: the thread
177
+ * is named by `conversation_id`.
178
+ */
179
+ interface ChatUrgencyFlaggedPayload extends OpenEventPayload {
180
+ readonly object: 'chat_urgency';
181
+ readonly user_ref: string;
182
+ readonly conversation_id: string;
183
+ /** The assistant message that carries the verdict. */
184
+ readonly message_id: string;
185
+ /** `emergency` today (`FLAGGED_URGENCY_LEVELS`); the level set can grow. */
186
+ readonly urgency_level: string;
187
+ }
188
+ /** Which of the two memory nudges is waiting in the pet's chat (`REMINDER_KIND_BY_TRIGGER`). A closed code. */
189
+ type EverfurChatReminderKind = 'medication_due' | 'open_concern';
190
+ /**
191
+ * `chat.reminder_due` (CRN-18): the consumer app's medication reminder, or its one gentle check-in on an unresolved
192
+ * concern, is waiting in the pet's chat. One per (pet, kind, due day), under the same claim, pause and opt-out fences
193
+ * the consumer push has. Ids and a closed kind: never the medicine, the symptom or the nudge sentence.
194
+ */
195
+ interface ChatReminderDuePayload extends OpenEventPayload {
196
+ readonly object: 'chat_reminder';
197
+ readonly user_ref: string;
198
+ readonly pet_ref: string;
199
+ /** The thread the reminder lands in when one exists, else `null`. */
200
+ readonly conversation_id: string | null;
201
+ readonly kind: EverfurChatReminderKind;
202
+ /** ISO 8601. When the nudge became due. */
203
+ readonly due_at: string;
204
+ }
205
+ /**
206
+ * The closed classes of thing a parsed record can hold (`copy/records_activation.py` RECORD_CLASSES), in the
207
+ * order the platform counts them. A `record.activation` event names exactly one of these.
208
+ */
209
+ type EverfurRecordClass = 'weight_history' | 'vaccinations' | 'medications' | 'bloodwork' | 'diagnoses';
210
+ /**
211
+ * `record.activation` (CRN-19): a requested record was read and something was found in it, so a member is told
212
+ * WHAT was found rather than only that records are ready.
213
+ *
214
+ * ONE EVENT PER NON-EMPTY CLASS, the way the consumer app sends one paced push per class: `record_class` names
215
+ * the class this event is about and `count` is how many rows of it the parse found. `counts` carries all five
216
+ * for the same request, so a single event is enough to render a summary. Counts and a closed class name only:
217
+ * never a weight, a drug, a result or a diagnosis.
218
+ *
219
+ * SEVERAL OF THESE FOR ONE REQUEST IS NORMAL, not a duplicate: one per non-empty class, deduped by the
220
+ * platform on `request:class`. An empty class produces no event at all, so never wait for a zero-count ping,
221
+ * and never dedupe your own handling on `request_id` alone or you will swallow every class but the first.
222
+ */
223
+ interface RecordActivationPayload extends OpenEventPayload {
224
+ readonly object: 'record_activation';
225
+ readonly request_id: string;
226
+ readonly user_ref: string;
227
+ readonly pet_ref: string;
228
+ /** Which class this event is about. One event per non-empty class of one request. */
229
+ readonly record_class: EverfurRecordClass;
230
+ /** How many rows of `record_class` the parse found. Always at least 1: an empty class sends nothing. */
231
+ readonly count: number;
232
+ /** All five counts for the same request, so one event can render the whole summary. */
233
+ readonly counts: Readonly<Record<EverfurRecordClass, number>>;
234
+ }
235
+ /** `webhook_endpoint.test`: sent when you press Send test on an endpoint. Names the endpoint it was sent to. */
236
+ interface WebhookEndpointTestPayload extends OpenEventPayload {
237
+ readonly object: 'webhook_endpoint';
238
+ readonly endpoint_id: string;
239
+ }
240
+ /** Payload type for each outbound event type. */
241
+ interface EverfurWebhookPayloadMap {
242
+ readonly 'member.linked': MemberLinkPayload;
243
+ readonly 'member.unlinked': MemberLinkPayload;
244
+ readonly 'visit.booked': VisitPayload;
245
+ readonly 'visit.cancelled': VisitPayload;
246
+ readonly 'visit.completed': VisitPayload;
247
+ readonly 'visit.no_show': VisitPayload;
248
+ readonly 'record_request.updated': RecordRequestUpdatedPayload;
249
+ readonly 'record.ready': RecordReadyPayload;
250
+ readonly 'webhook_endpoint.test': WebhookEndpointTestPayload;
251
+ readonly 'chat.follow_up_due': ChatFollowUpDuePayload;
252
+ readonly 'chat.urgency.flagged': ChatUrgencyFlaggedPayload;
253
+ readonly 'pet.vaccination.due': PetVaccinationDuePayload;
254
+ readonly 'visit.rescheduled': VisitRescheduledPayload;
255
+ readonly 'visit.reminder': VisitReminderPayload;
256
+ readonly 'visit.followup_sent': VisitFollowupSentPayload;
257
+ readonly 'chat.reminder_due': ChatReminderDuePayload;
258
+ readonly 'record.activation': RecordActivationPayload;
259
+ readonly 'visit.message_received': VisitMessageReceivedPayload;
260
+ readonly 'visit.ended': VisitEndedPayload;
261
+ }
262
+ /** The signed envelope of one outbound event of type `T`. */
263
+ interface EverfurWebhookEventOf<T extends EverfurWebhookEventType> {
264
+ /** `evt_...`. Unique per event; a manual resend reuses it on purpose, so dedupe on it. */
265
+ readonly id: string;
266
+ readonly object: 'event';
267
+ readonly type: T;
268
+ /** The payload version, for example `2026-09-15`. */
269
+ readonly api_version: string;
270
+ /** Unix seconds when the event was created (not when it was delivered). */
271
+ readonly created: number;
272
+ /** `false` for a sandbox (test) tenant. */
273
+ readonly livemode: boolean;
274
+ readonly data: {
275
+ readonly object: EverfurWebhookPayloadMap[T];
276
+ };
277
+ }
278
+ /**
279
+ * A verified outbound event whose type is in the catalog. After `isEverfurWebhookEvent(event)`, narrow on
280
+ * `type`: `if (event.type === 'record.ready') event.data.object.request_id`.
281
+ */
282
+ type EverfurWebhookEvent = {
283
+ [T in EverfurWebhookEventType]: EverfurWebhookEventOf<T>;
284
+ }[EverfurWebhookEventType];
285
+ /**
286
+ * A verified outbound event whose type this SDK version does not know (a type added after it shipped).
287
+ * `constructEvent` returns it rather than throwing, because the signature is valid and the right answer to an
288
+ * event you do not handle is still a 2xx. Separate it with `isEverfurWebhookEvent` before narrowing on `type`.
289
+ */
290
+ interface UnrecognizedEverfurWebhookEvent {
291
+ readonly id: string;
292
+ readonly object: 'event';
293
+ readonly type: string;
294
+ readonly api_version: string;
295
+ readonly created: number;
296
+ readonly livemode: boolean;
297
+ readonly data: {
298
+ readonly object: OpenEventPayload;
299
+ };
300
+ }
301
+ /** True when `type` is in this SDK version's outbound catalog. */
302
+ declare function isEverfurWebhookEventType(type: unknown): type is EverfurWebhookEventType;
303
+ /**
304
+ * Separates a catalog event from one this SDK version does not know, so a `switch (event.type)` narrows the
305
+ * payload. Answer 2xx to the other branch: Everfur retries anything else.
306
+ */
307
+ declare function isEverfurWebhookEvent(event: EverfurWebhookEvent | UnrecognizedEverfurWebhookEvent): event is EverfurWebhookEvent;
308
+ /** Every inbound event type in the v1 registry. Order matches EFBackend `INBOUND_EVENT_TYPES`. */
309
+ declare const PARTNER_INBOUND_EVENT_TYPES: readonly ["pet.profile.updated", "pet.incident.reported", "pet.behavior_note.added", "pet.service_score.recorded", "pet.deleted", "member.status_changed", "member.deleted"];
310
+ /** One inbound event type name. A `pet.*` type is about a pet (`petRef` required); a `member.*` type is not. */
311
+ type PartnerInboundEventType = (typeof PARTNER_INBOUND_EVENT_TYPES)[number];
312
+ /**
313
+ * `pet.profile.updated` schema_version 1: profile fields you are the system of record for. AUTHORITATIVE: it updates
314
+ * the pet profile itself, in the event's own transaction (PF-11), so an applied receipt never names a write that did
315
+ * not happen. Every field is optional and an absent field (or `null`) is unchanged: the event API has no clear, use
316
+ * `updatePartnerPet` for that. Strings are trimmed by Everfur before their length is checked. `date_of_birth` is
317
+ * recorded as the birth date at day precision and `neutered` as the spay status; for a pet that is not a dog or a
318
+ * cat those three are accepted and not applied (v1 is best effort there), while the identity fields still land.
319
+ */
320
+ interface PetProfileUpdatedData {
321
+ /** 1 to 64 characters. */
322
+ readonly name?: string | null;
323
+ /** 1 to 64 characters. */
324
+ readonly species?: string | null;
325
+ /** 1 to 128 characters. */
326
+ readonly breed?: string | null;
327
+ readonly sex?: 'male' | 'female' | 'unknown' | null;
328
+ /** `YYYY-MM-DD`. */
329
+ readonly date_of_birth?: string | null;
330
+ /** Greater than 0 and less than 500. */
331
+ readonly weight_kg?: number | null;
332
+ readonly neutered?: boolean | null;
333
+ }
334
+ /**
335
+ * `pet.incident.reported`. `incident_id` is the natural id: a later event with the same id replaces this one when
336
+ * its `occurredAt` is later.
337
+ */
338
+ interface PetIncidentReportedData {
339
+ /** Your id for the incident, 1 to 128 characters. */
340
+ readonly incident_id: string;
341
+ readonly category: 'injury' | 'illness' | 'behavior' | 'escape' | 'other';
342
+ readonly severity: 'low' | 'medium' | 'high';
343
+ readonly location_type: 'daycare' | 'boarding' | 'grooming' | 'walk' | 'training' | 'home' | 'other';
344
+ /** 1 to 2000 characters. */
345
+ readonly description: string;
346
+ /** Defaults to `false`. */
347
+ readonly resolved?: boolean;
348
+ }
349
+ /** `pet.behavior_note.added`. `note_id` is the natural id. */
350
+ interface PetBehaviorNoteAddedData {
351
+ /** Your id for the note, 1 to 128 characters. */
352
+ readonly note_id: string;
353
+ readonly context: 'daycare' | 'boarding' | 'grooming' | 'walk' | 'training' | 'other';
354
+ /** 1 to 2000 characters. */
355
+ readonly note: string;
356
+ readonly sentiment?: 'positive' | 'neutral' | 'concern' | null;
357
+ }
358
+ /** `pet.service_score.recorded`. `score_id` is the natural id. */
359
+ interface PetServiceScoreRecordedData {
360
+ /** Your id for the score, 1 to 128 characters. */
361
+ readonly score_id: string;
362
+ readonly service: 'daycare' | 'boarding' | 'grooming' | 'walk' | 'training';
363
+ /** An integer from 1 to 5. */
364
+ readonly score: number;
365
+ /** At most 2000 characters. */
366
+ readonly comment?: string | null;
367
+ }
368
+ /** `pet.deleted`: erases what you sent about this pet. */
369
+ interface PetDeletedData {
370
+ readonly reason?: 'owner_request' | 'deceased' | 'rehomed' | 'other' | null;
371
+ }
372
+ /** `member.status_changed`: the member's status in your service. */
373
+ interface MemberStatusChangedData {
374
+ readonly status: 'active' | 'paused' | 'cancelled' | 'lapsed';
375
+ /** At most 64 characters. */
376
+ readonly plan?: string | null;
377
+ /** `YYYY-MM-DD`. */
378
+ readonly effective_on?: string | null;
379
+ }
380
+ /** `member.deleted`: erases what you sent about this member. */
381
+ interface MemberDeletedData {
382
+ readonly reason?: 'owner_request' | 'account_closed' | 'other' | null;
383
+ }
384
+ /** The `data` schema of each inbound event type (schema version 1). */
385
+ interface PartnerInboundEventDataMap {
386
+ readonly 'pet.profile.updated': PetProfileUpdatedData;
387
+ readonly 'pet.incident.reported': PetIncidentReportedData;
388
+ readonly 'pet.behavior_note.added': PetBehaviorNoteAddedData;
389
+ readonly 'pet.service_score.recorded': PetServiceScoreRecordedData;
390
+ readonly 'pet.deleted': PetDeletedData;
391
+ readonly 'member.status_changed': MemberStatusChangedData;
392
+ readonly 'member.deleted': MemberDeletedData;
393
+ }
394
+ /** One event of type `T` your backend sends to Everfur. */
395
+ interface PartnerInboundEventOf<T extends PartnerInboundEventType> {
396
+ readonly type: T;
397
+ /**
398
+ * The schema version of `data`. Every type is at version 1; omit it or pass 1. `pet.profile.updated` also has
399
+ * version 2, the whole partner pet body (`PetProfileUpdatedV2Event`).
400
+ */
401
+ readonly schemaVersion?: 1;
402
+ /** Your opaque member id (the same one you mint sessions with). 1 to 128 printable characters, no `@`. */
403
+ readonly userRef: string;
404
+ /**
405
+ * Your opaque pet id, under the same rule as `userRef`. Required on a `pet.*` event and refused on a
406
+ * `member.*` event (`sendPartnerEvent` throws before sending either mistake).
407
+ */
408
+ readonly petRef?: string;
409
+ /**
410
+ * When it happened: a `Date`, or an ISO 8601 date-time string with an explicit offset (`Z` or `+05:30`). Everfur
411
+ * refuses a time older than 30 days or more than 5 minutes ahead of its clock.
412
+ */
413
+ readonly occurredAt: Date | string;
414
+ /** The type's fields. Closed: a field not in the type's schema is refused. */
415
+ readonly data: PartnerInboundEventDataMap[T];
416
+ }
417
+ /**
418
+ * `pet.profile.updated` schema_version 2 (PF-11): the whole partner pet body, health profile included, exactly what
419
+ * `upsertPartnerPet` takes. Everfur applies it through the same write path the pet routes use, onto the same tables,
420
+ * so what Everfur chat and an Everfur vet see is the same whichever door you use.
421
+ *
422
+ * - Absent is unchanged and there is NO CLEAR over the event API (nulls are dropped): use `updatePartnerPet` to clear.
423
+ * A health LIST you send is still the complete set you hold (set-replace, `[]` clears it).
424
+ * - A health field needs `pets.health.update` as well as `partner_events.inbound.create`, and a dog or a cat: any
425
+ * other species is the 422 `pet_health_species_unsupported` with nothing applied.
426
+ * - Version 2 rides the server pet API's own switch: while Everfur has it off, version 2 is refused exactly as a
427
+ * version that does not exist (400 `event_payload_invalid`).
428
+ * - A member you have not brought to Everfur is accepted and updates nothing; it never creates an account.
429
+ */
430
+ interface PetProfileUpdatedV2Event {
431
+ readonly type: 'pet.profile.updated';
432
+ readonly schemaVersion: 2;
433
+ /** Your opaque member id (the same one you mint sessions with). 1 to 128 printable characters, no `@`. */
434
+ readonly userRef: string;
435
+ /** Your opaque pet id, under the same rule as `userRef`. */
436
+ readonly petRef: string;
437
+ /** When it happened: a `Date`, or an ISO 8601 date-time string with an explicit offset. */
438
+ readonly occurredAt: Date | string;
439
+ /** The partner pet body, as `upsertPartnerPet` takes it. Only the fields it names are sent. */
440
+ readonly data: PartnerPetProfile;
441
+ }
442
+ /** One event your backend sends to Everfur. Narrow on `type` (and `schemaVersion`) to get that type's `data`. */
443
+ type PartnerInboundEvent = {
444
+ [T in PartnerInboundEventType]: PartnerInboundEventOf<T>;
445
+ }[PartnerInboundEventType] | PetProfileUpdatedV2Event;
446
+
447
+ /** The request header carrying the signature. Header lookups are case-insensitive in Node. */
448
+ declare const EVERFUR_SIGNATURE_HEADER = "Everfur-Signature";
449
+ /** Default replay window, in seconds, matching the platform. */
450
+ declare const DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300;
451
+ /** Why a delivery was refused. Programmer errors (no secret, a parsed body) throw `EverfurConfigError`. */
452
+ type WebhookVerificationFailure =
453
+ /** The header is missing, too long, or not `t=...,v1=...`. */
454
+ 'malformed_header'
455
+ /** The signed timestamp is outside the tolerance (a replay, or a clock that is far off). */
456
+ | 'timestamp_outside_tolerance'
457
+ /** No `v1` matches any of the secrets. Wrong secret, or the body was changed after signing. */
458
+ | 'no_matching_signature'
459
+ /** The signature is valid but the body is not an Everfur event envelope. */
460
+ | 'malformed_payload';
461
+ /** Thrown by `constructEvent` when a delivery must be refused. Answer it with a 400. */
462
+ declare class EverfurWebhookVerificationError extends Error {
463
+ readonly code: WebhookVerificationFailure;
464
+ constructor(code: WebhookVerificationFailure);
465
+ }
466
+ /** Options for `constructEvent`. */
467
+ interface ConstructEventOptions {
468
+ /** Replay window in seconds, applied both ways. Defaults to 300. */
469
+ readonly toleranceSeconds?: number;
470
+ /** The current time in unix seconds. For tests; defaults to the system clock. */
471
+ readonly nowSeconds?: number;
472
+ }
473
+ /** A raw request body: the exact bytes received, or those bytes decoded as UTF-8. Never parsed JSON. */
474
+ type WebhookPayload = string | Uint8Array;
475
+ /**
476
+ * Verify an Everfur webhook delivery and return the event it carries.
477
+ *
478
+ * Pass the RAW body (a `Buffer` from `express.raw()`, or `await request.text()`), the `Everfur-Signature`
479
+ * header, and your endpoint's signing secret. During a rotation pass both secrets. Throws
480
+ * `EverfurWebhookVerificationError` when the delivery must be refused (answer 400), and `EverfurConfigError`
481
+ * for a call that can never succeed (no secret, a parsed object for a body, a bad tolerance).
482
+ *
483
+ * The result may be an event type this SDK version does not know yet; `isEverfurWebhookEvent` separates the
484
+ * two before you switch on `type`. Deduplicate on `event.id`: a resend carries the same id on purpose.
485
+ */
486
+ declare function constructEvent(payload: WebhookPayload, signatureHeader: string | null | undefined, secrets: string | readonly string[], options?: ConstructEventOptions): EverfurWebhookEvent | UnrecognizedEverfurWebhookEvent;
487
+ /** Options for `generateTestSignatureHeader`. */
488
+ interface TestSignatureHeaderParams {
489
+ readonly payload: WebhookPayload;
490
+ /** Current secret first, then any grace secrets, the order Everfur sends them in. */
491
+ readonly secrets: string | readonly string[];
492
+ /** Unix seconds. Defaults to now. */
493
+ readonly timestamp?: number;
494
+ }
495
+ /**
496
+ * Build an `Everfur-Signature` header exactly as Everfur would, for testing your webhook handler with a
497
+ * test secret. Never needed in production.
498
+ */
499
+ declare function generateTestSignatureHeader(params: TestSignatureHeaderParams): string;
500
+
501
+ /** How your backend reaches Everfur. Build it once and reuse it for every event. */
502
+ interface PartnerEventsClient {
503
+ /** The Everfur API base URL, for example `https://api.everfur.com/api/v1`. https only (loopback excepted). */
504
+ readonly apiBaseUrl: string;
505
+ /**
506
+ * `sk_partner_...`, or an `rk_partner_...` restricted key carrying `partner_events.inbound.create`. Never shipped
507
+ * to a device.
508
+ */
509
+ readonly partnerSecretKey: string;
510
+ readonly contractVersion?: string;
511
+ readonly fetchImpl?: FetchLike;
512
+ }
513
+ /** What Everfur recorded for one inbound event: the 201 receipt. A replay of the same request answers the same one. */
514
+ interface PartnerEventReceipt {
515
+ /** `ievt_...`. */
516
+ readonly id: string;
517
+ readonly type: PartnerInboundEventType;
518
+ readonly schemaVersion: number;
519
+ readonly userRef: string;
520
+ /** The pet the event is about, or `null` for a member event. */
521
+ readonly petRef: string | null;
522
+ /** ISO 8601, in UTC, as Everfur stored it. */
523
+ readonly occurredAt: string;
524
+ /** ISO 8601, in UTC. */
525
+ readonly receivedAt: string;
526
+ /**
527
+ * `applied`, or `superseded` when an event for the same fact with a later `occurredAt` already landed. A later
528
+ * read of the event can also show `erased`, after a `pet.deleted` or `member.deleted`.
529
+ */
530
+ readonly status: string;
531
+ /** `false` for a sandbox (test) tenant. */
532
+ readonly livemode: boolean;
533
+ /** The key the request was sent with (the one you passed, or the one generated). */
534
+ readonly idempotencyKey: string;
535
+ }
536
+ /**
537
+ * Send one event about a member or a pet to Everfur.
538
+ *
539
+ * `idempotencyKey` makes a retry safe: send the same key with the same event and Everfur records it once (the
540
+ * SDK serialises one event to the same bytes every time). Omit it and a random key is generated, but it is only
541
+ * returned on a successful receipt: after a timeout or a network failure it is lost, and a resend gets a new key
542
+ * and can record the event twice. Pass your own key (an id from your system) whenever you might retry.
543
+ *
544
+ * Settles to an `EverfurResult` for HTTP and network failures. Throws `EverfurConfigError` for a request that can
545
+ * never be accepted: a malformed key or event, a pet event without `petRef` (or a member event with one), an
546
+ * `occurredAt` without an offset, or a body over 32 KB.
547
+ */
548
+ declare function sendPartnerEvent(client: PartnerEventsClient, event: PartnerInboundEvent, idempotencyKey?: string): Promise<EverfurResult<PartnerEventReceipt>>;
549
+
550
+ export { type ChatFollowUpDuePayload, type ChatReminderDuePayload, type ChatUrgencyFlaggedPayload, type ConstructEventOptions, DEFAULT_WEBHOOK_TOLERANCE_SECONDS, EVERFUR_SIGNATURE_HEADER, EVERFUR_WEBHOOK_EVENT_TYPES, EVERFUR_WEBHOOK_ONLY_EVENT_TYPES, type EverfurChatReminderKind, type EverfurRecordClass, type EverfurVaccinationDueStage, type EverfurVaccine, type EverfurVisitReminderStage, type EverfurVisitStatus, type EverfurWebhookEvent, type EverfurWebhookEventOf, type EverfurWebhookEventType, type EverfurWebhookOnlyEventType, type EverfurWebhookPayloadMap, EverfurWebhookVerificationError, type MemberDeletedData, type MemberLinkPayload, type MemberStatusChangedData, type OpenEventPayload, PARTNER_INBOUND_EVENT_TYPES, type PartnerEventReceipt, type PartnerEventsClient, type PartnerInboundEvent, type PartnerInboundEventDataMap, type PartnerInboundEventOf, type PartnerInboundEventType, PartnerPetProfile, type PetBehaviorNoteAddedData, type PetDeletedData, type PetIncidentReportedData, type PetProfileUpdatedData, type PetProfileUpdatedV2Event, type PetServiceScoreRecordedData, type PetVaccinationDuePayload, type RecordActivationPayload, type RecordReadyPayload, type RecordRequestSimpleStatus, type RecordRequestUpdatedPayload, type TestSignatureHeaderParams, type UnrecognizedEverfurWebhookEvent, type VisitEndedPayload, type VisitFollowupSentPayload, type VisitMessageReceivedPayload, type VisitPayload, type VisitReminderPayload, type VisitRescheduledPayload, type WebhookEndpointTestPayload, type WebhookPayload, type WebhookVerificationFailure, constructEvent, generateTestSignatureHeader, isEverfurWebhookEvent, isEverfurWebhookEventType, sendPartnerEvent };