hubble-sdk-python 0.2.1__tar.gz → 0.3.0__tar.gz

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 (79) hide show
  1. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/CHANGELOG.md +29 -0
  2. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/PKG-INFO +45 -16
  3. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/README.md +44 -15
  4. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/__init__.py +24 -4
  5. hubble_sdk_python-0.3.0/hubble_sdk/_generated/api/default/create_consent.py +193 -0
  6. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/create_consent_link.py +8 -4
  7. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/export_patient_fhir.py +31 -12
  8. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/export_patient_pdf.py +36 -12
  9. hubble_sdk_python-0.3.0/hubble_sdk/_generated/api/default/get_application_token.py +194 -0
  10. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/get_patient_pdf_export.py +47 -20
  11. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/list_consents.py +16 -4
  12. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/read_fhir.py +48 -13
  13. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/__init__.py +20 -0
  14. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/application_token_error.py +54 -0
  15. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/application_token_error_error.py +31 -0
  16. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/application_token_request.py +72 -0
  17. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/application_token_response.py +69 -0
  18. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/attach_client_authorization_body.py +1 -1
  19. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/client_supplied_discloser.py +107 -0
  20. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/client_supplied_discloser_facility_type.py +28 -0
  21. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent.py +5 -4
  22. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/created_consent.py +152 -0
  23. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/facility_address.py +78 -0
  24. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/facility_address_state.py +77 -0
  25. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/patient_address.py +13 -5
  26. hubble_sdk_python-0.3.0/hubble_sdk/_generated/models/patient_address_state.py +77 -0
  27. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/patient_demographics.py +1 -1
  28. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/provider_seed.py +2 -1
  29. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_hubble.py +281 -41
  30. hubble_sdk_python-0.3.0/hubble_sdk/_params.py +86 -0
  31. hubble_sdk_python-0.3.0/hubble_sdk/py.typed +0 -0
  32. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/pydoc-markdown.yml +4 -3
  33. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/pyproject.toml +1 -1
  34. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/tests/test_hubble.py +326 -9
  35. hubble_sdk_python-0.3.0/tests/test_params.py +68 -0
  36. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/.gitignore +0 -0
  37. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/LICENSE +0 -0
  38. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/config.yaml +0 -0
  39. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/__init__.py +0 -0
  40. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/__init__.py +0 -0
  41. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/__init__.py +0 -0
  42. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/attach_client_authorization.py +0 -0
  43. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/exchange_token.py +0 -0
  44. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/get_consent.py +0 -0
  45. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/api/default/revoke_consent.py +0 -0
  46. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/client.py +0 -0
  47. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/errors.py +0 -0
  48. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/api_error.py +0 -0
  49. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_error.py +0 -0
  50. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_link_request.py +0 -0
  51. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_list.py +0 -0
  52. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_source.py +0 -0
  53. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_source_status.py +0 -0
  54. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_source_type.py +0 -0
  55. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/consent_status.py +0 -0
  56. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/device_authorization_request.py +0 -0
  57. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/device_authorization_response.py +0 -0
  58. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/export_patient_fhir_prefer.py +0 -0
  59. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/export_patient_fhir_response_202.py +0 -0
  60. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/export_patient_fhir_response_202_status.py +0 -0
  61. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/export_patient_pdf_prefer.py +0 -0
  62. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/export_patient_pdf_response_202.py +0 -0
  63. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/export_patient_pdf_response_202_status.py +0 -0
  64. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/fhir_resource.py +0 -0
  65. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/get_patient_pdf_export_download.py +0 -0
  66. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/get_patient_pdf_export_response_200.py +0 -0
  67. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/get_patient_pdf_export_response_200_status.py +0 -0
  68. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/o_auth_error.py +0 -0
  69. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/o_auth_error_error.py +0 -0
  70. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/operation_outcome.py +0 -0
  71. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/operation_outcome_issue_item.py +0 -0
  72. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/token_request.py +0 -0
  73. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/token_request_grant_type.py +0 -0
  74. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/models/token_response.py +0 -0
  75. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_generated/types.py +0 -0
  76. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/hubble_sdk/_webhooks.py +0 -0
  77. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/templates/property_templates/enum_property.py.jinja +0 -0
  78. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/templates/str_enum.py.jinja +0 -0
  79. {hubble_sdk_python-0.2.1 → hubble_sdk_python-0.3.0}/tests/test_webhooks.py +0 -0
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.0](https://github.com/hubble-dot-ai/hubble-sdks/compare/hubble-sdk-python-v0.2.1...hubble-sdk-python-v0.3.0) (2026-10-27)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * type the consent status filter as a literal ([#70](https://github.com/hubble-dot-ai/hubble-sdks/issues/70))
9
+ * each discloser needs an address (line1, city, state, postal_code) next to its name. The API now refuses a name-only discloser with a 400, and the TypeScript type no longer accepts one.
10
+
11
+ ### Features
12
+
13
+ * create consents without the device flow ([#66](https://github.com/hubble-dot-ai/hubble-sdks/issues/66)) ([f82bed9](https://github.com/hubble-dot-ai/hubble-sdks/commit/f82bed9d31192144cd592c25890639b1576bf2bd))
14
+ * read consents with an application access token ([#65](https://github.com/hubble-dot-ai/hubble-sdks/issues/65)) ([66f9703](https://github.com/hubble-dot-ai/hubble-sdks/commit/66f97031f9eef15bc39c2e5a8f6059c11c4bbf93))
15
+ * send facility details with each discloser when attaching an authorization ([#69](https://github.com/hubble-dot-ai/hubble-sdks/issues/69)) ([6d49b68](https://github.com/hubble-dot-ai/hubble-sdks/commit/6d49b68b49768efb5715cc7a3379ee0123ddd466))
16
+ * ship a py.typed marker so type checkers read the SDK's types ([#72](https://github.com/hubble-dot-ai/hubble-sdks/issues/72)) ([bf1f4b0](https://github.com/hubble-dot-ai/hubble-sdks/commit/bf1f4b0a0ecadc17d89e0eb477cbda98f9648aec))
17
+ * sync the spec for application tokens and POST /consents ([#64](https://github.com/hubble-dot-ai/hubble-sdks/issues/64)) ([8981d57](https://github.com/hubble-dot-ai/hubble-sdks/commit/8981d57c7dee236a1668effc477adbd77ef38ba3))
18
+ * type the consent status filter as a literal ([#70](https://github.com/hubble-dot-ai/hubble-sdks/issues/70)) ([fb7fd4b](https://github.com/hubble-dot-ai/hubble-sdks/commit/fb7fd4b26ba0e05874a01a307ca8e16a02000979))
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * harden application-token reads (dot ids, relative next links, shared token) ([#68](https://github.com/hubble-dot-ai/hubble-sdks/issues/68)) ([0d9d41e](https://github.com/hubble-dot-ai/hubble-sdks/commit/0d9d41e85f5d45f98a7cc08d7efb1ede6a1aabbd))
24
+ * send create_consent's body as given so a misspelt field is refused ([#73](https://github.com/hubble-dot-ai/hubble-sdks/issues/73)) ([559cf0f](https://github.com/hubble-dot-ai/hubble-sdks/commit/559cf0f7471f277f77d874f4454d5202d3a16e62))
25
+ * sync the consent status and error descriptions from the portal ([#62](https://github.com/hubble-dot-ai/hubble-sdks/issues/62)) ([2bd1606](https://github.com/hubble-dot-ai/hubble-sdks/commit/2bd160636fa5ccd8d5f324d0d69f29ab19ff57fc))
26
+
27
+
28
+ ### Documentation
29
+
30
+ * keep the disclosers description in one argument entry ([#74](https://github.com/hubble-dot-ai/hubble-sdks/issues/74)) ([53e5163](https://github.com/hubble-dot-ai/hubble-sdks/commit/53e51634c5a29c0b3bd96dab06b8965f7b6cfdda))
31
+
3
32
  ## [0.2.1](https://github.com/hubble-dot-ai/hubble-sdks/compare/hubble-sdk-python-v0.2.0...hubble-sdk-python-v0.2.1) (2026-10-14)
4
33
 
5
34
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hubble-sdk-python
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Python client for the Hubble Patient Access API.
5
5
  Project-URL: Homepage, https://github.com/hubble-dot-ai/hubble-sdks
6
6
  Project-URL: Repository, https://github.com/hubble-dot-ai/hubble-sdks
@@ -32,8 +32,8 @@ Description-Content-Type: text/markdown
32
32
 
33
33
  # hubble-sdk-python
34
34
 
35
- Python client for the Hubble Patient Access API: create patient authorization
36
- links, exchange them for consent-scoped access tokens, and read FHIR R4 data.
35
+ Python client for the Hubble Patient Access API: create consents and patient
36
+ links, and read FHIR R4 data with your application's access token.
37
37
 
38
38
  ```bash
39
39
  pip install hubble-sdk-python
@@ -44,24 +44,53 @@ from hubble_sdk import Hubble
44
44
 
45
45
  hub = Hubble(client_id="hbl_client_prod_...", client_secret="hbl_prod_...")
46
46
 
47
- # 1. Create a patient link and send the patient to it. Optionally prefill with
47
+ # 1. Create a consent and send the patient its link. Optionally prefill with
48
48
  # patient={"first_name": ...} demographics, providers=[{"name": ...}], and
49
49
  # the optional organization your verified Hubble organization represents.
50
- link = hub.create_link(patient_ref="abc123", on_behalf_of_organization_name="Acme Health")
51
- print(link.verification_uri_complete)
52
-
53
- # 2. Wait for the patient to authorize (polls the token endpoint for you).
54
- session = hub.wait_for_authorization(link)
50
+ consent = hub.create_consent(patient_ref="abc123", on_behalf_of_organization_name="Acme Health")
51
+ print(consent.link_url) # returned only here; store it if you may resend it
55
52
 
56
- # 3. Read the patient's FHIR data (Bearer token + auto-refresh handled for you).
57
- bundle = session.everything()
58
- observations = session.fhir("Observation", params={"category": "vital-signs"})
59
- export = session.export_pdf() # export.content bytes; export.sources_failed counts failed sources
53
+ # 2. Read the patient's FHIR data whenever you like (see below for every read).
54
+ summary = hub.summary(consent.id)
55
+ labs = hub.search(consent.id, "Observation", {"category": "laboratory"})
60
56
 
61
57
  # Consent management
62
- for consent in hub.list_consents(status="active"):
63
- print(consent.id, consent.patient_ref)
64
- hub.revoke_consent(session.consent_id)
58
+ for c in hub.list_consents(status="active"):
59
+ print(c.id, c.patient_ref)
60
+ hub.revoke_consent(consent.id)
61
+ ```
62
+
63
+ ## Reading with an application token
64
+
65
+ Read any consent in your environment by its id, without the device flow: while
66
+ the patient is still adding sources, after they finish, or after the link
67
+ expires. The client gets the application access token from `POST /api/v1/token`,
68
+ caches it and renews it for you, and names the consent on every request. One
69
+ `Hubble` client is safe to share across threads: they share the one token, and
70
+ only one thread fetches or renews it at a time.
71
+
72
+ ```python
73
+ obs = hub.read(consent_id, "Observation", "abc-123") # one resource
74
+ page = hub.search(consent_id, "Observation", {"category": "laboratory"}) # first page (a Bundle)
75
+ for resource in hub.iter_search(consent_id, "Observation", {"category": "laboratory"}):
76
+ ... # every page, lazily
77
+ summary = hub.summary(consent_id)
78
+ record = hub.everything(consent_id, {"_count": 100})
79
+ export = hub.export_pdf(consent_id, connection=connection_id) # one source's PDF
80
+ ```
81
+
82
+ Reuse one `Hubble` client so its token is reused too.
83
+
84
+ ### The device flow
85
+
86
+ Existing integrations can keep using the device flow, which waits for the
87
+ patient to finish and reads with a consent-scoped token:
88
+
89
+ ```python
90
+ link = hub.create_link(patient_ref="abc123")
91
+ print(link.verification_uri_complete)
92
+ session = hub.wait_for_authorization(link) # polls until the patient finishes
93
+ bundle = session.everything() # refreshes the consent token for you
65
94
  ```
66
95
 
67
96
  ## Receiving webhooks
@@ -1,7 +1,7 @@
1
1
  # hubble-sdk-python
2
2
 
3
- Python client for the Hubble Patient Access API: create patient authorization
4
- links, exchange them for consent-scoped access tokens, and read FHIR R4 data.
3
+ Python client for the Hubble Patient Access API: create consents and patient
4
+ links, and read FHIR R4 data with your application's access token.
5
5
 
6
6
  ```bash
7
7
  pip install hubble-sdk-python
@@ -12,24 +12,53 @@ from hubble_sdk import Hubble
12
12
 
13
13
  hub = Hubble(client_id="hbl_client_prod_...", client_secret="hbl_prod_...")
14
14
 
15
- # 1. Create a patient link and send the patient to it. Optionally prefill with
15
+ # 1. Create a consent and send the patient its link. Optionally prefill with
16
16
  # patient={"first_name": ...} demographics, providers=[{"name": ...}], and
17
17
  # the optional organization your verified Hubble organization represents.
18
- link = hub.create_link(patient_ref="abc123", on_behalf_of_organization_name="Acme Health")
19
- print(link.verification_uri_complete)
20
-
21
- # 2. Wait for the patient to authorize (polls the token endpoint for you).
22
- session = hub.wait_for_authorization(link)
18
+ consent = hub.create_consent(patient_ref="abc123", on_behalf_of_organization_name="Acme Health")
19
+ print(consent.link_url) # returned only here; store it if you may resend it
23
20
 
24
- # 3. Read the patient's FHIR data (Bearer token + auto-refresh handled for you).
25
- bundle = session.everything()
26
- observations = session.fhir("Observation", params={"category": "vital-signs"})
27
- export = session.export_pdf() # export.content bytes; export.sources_failed counts failed sources
21
+ # 2. Read the patient's FHIR data whenever you like (see below for every read).
22
+ summary = hub.summary(consent.id)
23
+ labs = hub.search(consent.id, "Observation", {"category": "laboratory"})
28
24
 
29
25
  # Consent management
30
- for consent in hub.list_consents(status="active"):
31
- print(consent.id, consent.patient_ref)
32
- hub.revoke_consent(session.consent_id)
26
+ for c in hub.list_consents(status="active"):
27
+ print(c.id, c.patient_ref)
28
+ hub.revoke_consent(consent.id)
29
+ ```
30
+
31
+ ## Reading with an application token
32
+
33
+ Read any consent in your environment by its id, without the device flow: while
34
+ the patient is still adding sources, after they finish, or after the link
35
+ expires. The client gets the application access token from `POST /api/v1/token`,
36
+ caches it and renews it for you, and names the consent on every request. One
37
+ `Hubble` client is safe to share across threads: they share the one token, and
38
+ only one thread fetches or renews it at a time.
39
+
40
+ ```python
41
+ obs = hub.read(consent_id, "Observation", "abc-123") # one resource
42
+ page = hub.search(consent_id, "Observation", {"category": "laboratory"}) # first page (a Bundle)
43
+ for resource in hub.iter_search(consent_id, "Observation", {"category": "laboratory"}):
44
+ ... # every page, lazily
45
+ summary = hub.summary(consent_id)
46
+ record = hub.everything(consent_id, {"_count": 100})
47
+ export = hub.export_pdf(consent_id, connection=connection_id) # one source's PDF
48
+ ```
49
+
50
+ Reuse one `Hubble` client so its token is reused too.
51
+
52
+ ### The device flow
53
+
54
+ Existing integrations can keep using the device flow, which waits for the
55
+ patient to finish and reads with a consent-scoped token:
56
+
57
+ ```python
58
+ link = hub.create_link(patient_ref="abc123")
59
+ print(link.verification_uri_complete)
60
+ session = hub.wait_for_authorization(link) # polls until the patient finishes
61
+ bundle = session.everything() # refreshes the consent token for you
33
62
  ```
34
63
 
35
64
  ## Receiving webhooks
@@ -5,10 +5,12 @@ Import the high-level client from here:
5
5
  from hubble_sdk import Hubble
6
6
 
7
7
  hub = Hubble(client_id="hbl_client_...", client_secret="hbl_prod_...")
8
- link = hub.create_link(patient_ref="abc123")
9
- print(link.verification_uri_complete) # send the patient here
10
- session = hub.wait_for_authorization(link)
11
- bundle = session.everything() # reads FHIR with the consent token
8
+ consent = hub.create_consent(patient_ref="abc123")
9
+ print(consent.link_url) # send the patient here
10
+ bundle = hub.everything(consent.id) # read whenever you like
11
+
12
+ The device flow (``create_link`` / ``wait_for_authorization``) still works for
13
+ existing integrations.
12
14
 
13
15
  The generated low-level client lives under ``hubble_sdk._generated``
14
16
  if you need direct access to raw operations and models.
@@ -17,6 +19,7 @@ if you need direct access to raw operations and models.
17
19
  from ._generated.models import (
18
20
  Consent,
19
21
  ConsentStatus,
22
+ CreatedConsent,
20
23
  DeviceAuthorizationResponse,
21
24
  TokenResponse,
22
25
  )
@@ -28,6 +31,15 @@ from ._hubble import (
28
31
  PdfExport,
29
32
  TokenSet,
30
33
  )
34
+ from ._params import (
35
+ ConsentStatusFilter,
36
+ DiscloserParams,
37
+ FacilityAddressParams,
38
+ PatientAddressParams,
39
+ PatientParams,
40
+ ProviderSeedParams,
41
+ UsStateCode,
42
+ )
31
43
  from ._webhooks import (
32
44
  WEBHOOK_SIGNATURE_HEADER,
33
45
  WebhookEvent,
@@ -43,6 +55,13 @@ __all__ = [
43
55
  "ConsentTimeout",
44
56
  "TokenSet",
45
57
  "PdfExport",
58
+ "ConsentStatusFilter",
59
+ "PatientParams",
60
+ "PatientAddressParams",
61
+ "ProviderSeedParams",
62
+ "DiscloserParams",
63
+ "FacilityAddressParams",
64
+ "UsStateCode",
46
65
  "construct_webhook_event",
47
66
  "WebhookEvent",
48
67
  "WebhookEventSource",
@@ -50,6 +69,7 @@ __all__ = [
50
69
  "WEBHOOK_SIGNATURE_HEADER",
51
70
  "Consent",
52
71
  "ConsentStatus",
72
+ "CreatedConsent",
53
73
  "DeviceAuthorizationResponse",
54
74
  "TokenResponse",
55
75
  ]
@@ -0,0 +1,193 @@
1
+ from http import HTTPStatus
2
+ from typing import Any
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...models.api_error import ApiError
9
+ from ...models.consent_link_request import ConsentLinkRequest
10
+ from ...models.created_consent import CreatedConsent
11
+ from ...types import UNSET, Response, Unset
12
+
13
+
14
+ def _get_kwargs(
15
+ *,
16
+ body: ConsentLinkRequest | Unset = UNSET,
17
+ ) -> dict[str, Any]:
18
+ headers: dict[str, Any] = {}
19
+
20
+ _kwargs: dict[str, Any] = {
21
+ "method": "post",
22
+ "url": "/api/v1/consents",
23
+ }
24
+
25
+ if not isinstance(body, Unset):
26
+ _kwargs["json"] = body.to_dict()
27
+
28
+ headers["Content-Type"] = "application/json"
29
+
30
+ _kwargs["headers"] = headers
31
+ return _kwargs
32
+
33
+
34
+ def _parse_response(
35
+ *, client: AuthenticatedClient | Client, response: httpx.Response
36
+ ) -> ApiError | CreatedConsent | None:
37
+ if response.status_code == 201:
38
+ response_201 = CreatedConsent.from_dict(response.json())
39
+
40
+ return response_201
41
+
42
+ if response.status_code == 400:
43
+ response_400 = ApiError.from_dict(response.json())
44
+
45
+ return response_400
46
+
47
+ if response.status_code == 401:
48
+ response_401 = ApiError.from_dict(response.json())
49
+
50
+ return response_401
51
+
52
+ if response.status_code == 403:
53
+ response_403 = ApiError.from_dict(response.json())
54
+
55
+ return response_403
56
+
57
+ if client.raise_on_unexpected_status:
58
+ raise errors.UnexpectedStatus(response.status_code, response.content)
59
+ else:
60
+ return None
61
+
62
+
63
+ def _build_response(
64
+ *, client: AuthenticatedClient | Client, response: httpx.Response
65
+ ) -> Response[ApiError | CreatedConsent]:
66
+ return Response(
67
+ status_code=HTTPStatus(response.status_code),
68
+ content=response.content,
69
+ headers=response.headers,
70
+ parsed=_parse_response(client=client, response=response),
71
+ )
72
+
73
+
74
+ def sync_detailed(
75
+ *,
76
+ client: AuthenticatedClient,
77
+ body: ConsentLinkRequest | Unset = UNSET,
78
+ ) -> Response[ApiError | CreatedConsent]:
79
+ """Create a consent
80
+
81
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
82
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
83
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
84
+
85
+ Args:
86
+ body (ConsentLinkRequest | Unset):
87
+
88
+ Raises:
89
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
90
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
91
+
92
+ Returns:
93
+ Response[ApiError | CreatedConsent]
94
+ """
95
+
96
+ kwargs = _get_kwargs(
97
+ body=body,
98
+ )
99
+
100
+ response = client.get_httpx_client().request(
101
+ **kwargs,
102
+ )
103
+
104
+ return _build_response(client=client, response=response)
105
+
106
+
107
+ def sync(
108
+ *,
109
+ client: AuthenticatedClient,
110
+ body: ConsentLinkRequest | Unset = UNSET,
111
+ ) -> ApiError | CreatedConsent | None:
112
+ """Create a consent
113
+
114
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
115
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
116
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
117
+
118
+ Args:
119
+ body (ConsentLinkRequest | Unset):
120
+
121
+ Raises:
122
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
123
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
124
+
125
+ Returns:
126
+ ApiError | CreatedConsent
127
+ """
128
+
129
+ return sync_detailed(
130
+ client=client,
131
+ body=body,
132
+ ).parsed
133
+
134
+
135
+ async def asyncio_detailed(
136
+ *,
137
+ client: AuthenticatedClient,
138
+ body: ConsentLinkRequest | Unset = UNSET,
139
+ ) -> Response[ApiError | CreatedConsent]:
140
+ """Create a consent
141
+
142
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
143
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
144
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
145
+
146
+ Args:
147
+ body (ConsentLinkRequest | Unset):
148
+
149
+ Raises:
150
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
151
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
152
+
153
+ Returns:
154
+ Response[ApiError | CreatedConsent]
155
+ """
156
+
157
+ kwargs = _get_kwargs(
158
+ body=body,
159
+ )
160
+
161
+ response = await client.get_async_httpx_client().request(**kwargs)
162
+
163
+ return _build_response(client=client, response=response)
164
+
165
+
166
+ async def asyncio(
167
+ *,
168
+ client: AuthenticatedClient,
169
+ body: ConsentLinkRequest | Unset = UNSET,
170
+ ) -> ApiError | CreatedConsent | None:
171
+ """Create a consent
172
+
173
+ Creates a pending consent and its patient link, and returns the consent with `link_url`. Deliver the
174
+ link to the patient, then read the consent with an application access token from POST /api/v1/token
175
+ and `consent=<id>` on /api/v1/fhir. Every field is optional.
176
+
177
+ Args:
178
+ body (ConsentLinkRequest | Unset):
179
+
180
+ Raises:
181
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
182
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
183
+
184
+ Returns:
185
+ ApiError | CreatedConsent
186
+ """
187
+
188
+ return (
189
+ await asyncio_detailed(
190
+ client=client,
191
+ body=body,
192
+ )
193
+ ).parsed
@@ -77,7 +77,8 @@ def sync_detailed(
77
77
  Mints a pending consent and a one-time patient link. Send the patient to
78
78
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
79
79
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
80
- consent.
80
+ consent. To read with an application access token instead, create the consent with POST
81
+ /api/v1/consents, which has no device code.
81
82
 
82
83
  Args:
83
84
  body (ConsentLinkRequest | Unset):
@@ -112,7 +113,8 @@ def sync(
112
113
  Mints a pending consent and a one-time patient link. Send the patient to
113
114
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
114
115
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
115
- consent.
116
+ consent. To read with an application access token instead, create the consent with POST
117
+ /api/v1/consents, which has no device code.
116
118
 
117
119
  Args:
118
120
  body (ConsentLinkRequest | Unset):
@@ -142,7 +144,8 @@ async def asyncio_detailed(
142
144
  Mints a pending consent and a one-time patient link. Send the patient to
143
145
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
144
146
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
145
- consent.
147
+ consent. To read with an application access token instead, create the consent with POST
148
+ /api/v1/consents, which has no device code.
146
149
 
147
150
  Args:
148
151
  body (ConsentLinkRequest | Unset):
@@ -175,7 +178,8 @@ async def asyncio(
175
178
  Mints a pending consent and a one-time patient link. Send the patient to
176
179
  `verification_uri_complete`, then poll the token endpoint with `device_code` until they authorize.
177
180
  Accepts a nested JSON body (recommended) or the flat RFC 8628 form encoding; both prefill the same
178
- consent.
181
+ consent. To read with an application access token instead, create the consent with POST
182
+ /api/v1/consents, which has no device code.
179
183
 
180
184
  Args:
181
185
  body (ConsentLinkRequest | Unset):
@@ -1,5 +1,6 @@
1
1
  from http import HTTPStatus
2
2
  from typing import Any
3
+ from uuid import UUID
3
4
 
4
5
  import httpx
5
6
 
@@ -14,6 +15,7 @@ from ...types import UNSET, Response, Unset
14
15
 
15
16
  def _get_kwargs(
16
17
  *,
18
+ consent: UUID | Unset = UNSET,
17
19
  field_count: int | Unset = UNSET,
18
20
  field_offset: int | Unset = UNSET,
19
21
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -24,6 +26,11 @@ def _get_kwargs(
24
26
 
25
27
  params: dict[str, Any] = {}
26
28
 
29
+ json_consent: str | Unset = UNSET
30
+ if not isinstance(consent, Unset):
31
+ json_consent = str(consent)
32
+ params["consent"] = json_consent
33
+
27
34
  params["_count"] = field_count
28
35
 
29
36
  params["_offset"] = field_offset
@@ -103,6 +110,7 @@ def _build_response(
103
110
  def sync_detailed(
104
111
  *,
105
112
  client: AuthenticatedClient,
113
+ consent: UUID | Unset = UNSET,
106
114
  field_count: int | Unset = UNSET,
107
115
  field_offset: int | Unset = UNSET,
108
116
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -113,11 +121,12 @@ def sync_detailed(
113
121
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
114
122
  Bundle containing the captured provider sources, including each source's Patient and warnings for
115
123
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
116
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
117
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
118
- request for one already running reuses it. Payer records are not included.
124
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
125
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
126
+ one already running reuses it. Payer records are not included.
119
127
 
120
128
  Args:
129
+ consent (UUID | Unset):
121
130
  field_count (int | Unset):
122
131
  field_offset (int | Unset):
123
132
  prefer (ExportPatientFhirPrefer | Unset):
@@ -131,6 +140,7 @@ def sync_detailed(
131
140
  """
132
141
 
133
142
  kwargs = _get_kwargs(
143
+ consent=consent,
134
144
  field_count=field_count,
135
145
  field_offset=field_offset,
136
146
  prefer=prefer,
@@ -146,6 +156,7 @@ def sync_detailed(
146
156
  def sync(
147
157
  *,
148
158
  client: AuthenticatedClient,
159
+ consent: UUID | Unset = UNSET,
149
160
  field_count: int | Unset = UNSET,
150
161
  field_offset: int | Unset = UNSET,
151
162
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -156,11 +167,12 @@ def sync(
156
167
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
157
168
  Bundle containing the captured provider sources, including each source's Patient and warnings for
158
169
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
159
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
160
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
161
- request for one already running reuses it. Payer records are not included.
170
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
171
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
172
+ one already running reuses it. Payer records are not included.
162
173
 
163
174
  Args:
175
+ consent (UUID | Unset):
164
176
  field_count (int | Unset):
165
177
  field_offset (int | Unset):
166
178
  prefer (ExportPatientFhirPrefer | Unset):
@@ -175,6 +187,7 @@ def sync(
175
187
 
176
188
  return sync_detailed(
177
189
  client=client,
190
+ consent=consent,
178
191
  field_count=field_count,
179
192
  field_offset=field_offset,
180
193
  prefer=prefer,
@@ -184,6 +197,7 @@ def sync(
184
197
  async def asyncio_detailed(
185
198
  *,
186
199
  client: AuthenticatedClient,
200
+ consent: UUID | Unset = UNSET,
187
201
  field_count: int | Unset = UNSET,
188
202
  field_offset: int | Unset = UNSET,
189
203
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -194,11 +208,12 @@ async def asyncio_detailed(
194
208
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
195
209
  Bundle containing the captured provider sources, including each source's Patient and warnings for
196
210
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
197
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
198
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
199
- request for one already running reuses it. Payer records are not included.
211
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
212
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
213
+ one already running reuses it. Payer records are not included.
200
214
 
201
215
  Args:
216
+ consent (UUID | Unset):
202
217
  field_count (int | Unset):
203
218
  field_offset (int | Unset):
204
219
  prefer (ExportPatientFhirPrefer | Unset):
@@ -212,6 +227,7 @@ async def asyncio_detailed(
212
227
  """
213
228
 
214
229
  kwargs = _get_kwargs(
230
+ consent=consent,
215
231
  field_count=field_count,
216
232
  field_offset=field_offset,
217
233
  prefer=prefer,
@@ -225,6 +241,7 @@ async def asyncio_detailed(
225
241
  async def asyncio(
226
242
  *,
227
243
  client: AuthenticatedClient,
244
+ consent: UUID | Unset = UNSET,
228
245
  field_count: int | Unset = UNSET,
229
246
  field_offset: int | Unset = UNSET,
230
247
  prefer: ExportPatientFhirPrefer | Unset = UNSET,
@@ -235,11 +252,12 @@ async def asyncio(
235
252
  query parameters to prepare health-records.json in the background. The file is a FHIR collection
236
253
  Bundle containing the captured provider sources, including each source's Patient and warnings for
237
254
  incomplete sources. It has no paging links, search metadata or total field, and is not a Bulk Data
238
- $export/NDJSON response. Poll Content-Location with the same consent token no sooner than Retry-
239
- After for a 303 download redirect. An organization can hold 20 exports in flight at once; a repeat
240
- request for one already running reuses it. Payer records are not included.
255
+ $export/NDJSON response. Poll Content-Location with the same token no sooner than Retry-After for a
256
+ 303 download redirect. An organization can hold 20 exports in flight at once; a repeat request for
257
+ one already running reuses it. Payer records are not included.
241
258
 
242
259
  Args:
260
+ consent (UUID | Unset):
243
261
  field_count (int | Unset):
244
262
  field_offset (int | Unset):
245
263
  prefer (ExportPatientFhirPrefer | Unset):
@@ -255,6 +273,7 @@ async def asyncio(
255
273
  return (
256
274
  await asyncio_detailed(
257
275
  client=client,
276
+ consent=consent,
258
277
  field_count=field_count,
259
278
  field_offset=field_offset,
260
279
  prefer=prefer,