diff --git a/backend/cosmetology-app/bin/generate_mock_license_csv_upload_file.py b/backend/cosmetology-app/bin/generate_mock_license_csv_upload_file.py index d7554ad41..0523ac1c8 100755 --- a/backend/cosmetology-app/bin/generate_mock_license_csv_upload_file.py +++ b/backend/cosmetology-app/bin/generate_mock_license_csv_upload_file.py @@ -4,8 +4,8 @@ # The JSON file can be used for API testing or other purposes. # # Run from 'backend/compact-connect' like: -# bin/generate_mock_license_csv_upload_file.py --count 100 --compact octp --jurisdiction ne --format csv -# bin/generate_mock_license_csv_upload_file.py --count 100 --compact octp --jurisdiction ne --format json +# bin/generate_mock_license_csv_upload_file.py --count 100 --compact cosm --jurisdiction al --format csv +# bin/generate_mock_license_csv_upload_file.py --count 100 --compact cosm --jurisdiction al --format json import json import os import sys diff --git a/backend/cosmetology-app/bin/run_python_tests.py b/backend/cosmetology-app/bin/run_python_tests.py index 2d35ad977..22270123c 100755 --- a/backend/cosmetology-app/bin/run_python_tests.py +++ b/backend/cosmetology-app/bin/run_python_tests.py @@ -30,6 +30,7 @@ 'lambdas/python/disaster-recovery', 'lambdas/python/migration', 'lambdas/python/provider-data-v1', + 'lambdas/python/search', 'lambdas/python/staff-user-pre-token', 'lambdas/python/staff-users', '.', # CDK tests diff --git a/backend/cosmetology-app/docs/api-specification/latest-oas30.json b/backend/cosmetology-app/docs/api-specification/latest-oas30.json index a1d0e94a3..70ed01a4b 100644 --- a/backend/cosmetology-app/docs/api-specification/latest-oas30.json +++ b/backend/cosmetology-app/docs/api-specification/latest-oas30.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "StateApi", - "version": "2026-02-16T16:29:16Z" + "version": "2026-03-13T17:32:08Z" }, "servers": [ { @@ -74,7 +74,16 @@ { "SandboxStateAPIStackStateApiStateAuthAuthorizer7F83A6D3": [ "cosm/write", - "az/cosm.write" + "al/cosm.write", + "az/cosm.write", + "co/cosm.write", + "ks/cosm.write", + "ky/cosm.write", + "md/cosm.write", + "oh/cosm.write", + "tn/cosm.write", + "va/cosm.write", + "wa/cosm.write" ] } ] @@ -124,7 +133,16 @@ { "SandboxStateAPIStackStateApiStateAuthAuthorizer7F83A6D3": [ "cosm/write", - "az/cosm.write" + "al/cosm.write", + "az/cosm.write", + "co/cosm.write", + "ks/cosm.write", + "ky/cosm.write", + "md/cosm.write", + "oh/cosm.write", + "tn/cosm.write", + "va/cosm.write", + "wa/cosm.write" ] } ] diff --git a/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json b/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json index c69959e20..9e2056295 100644 --- a/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json +++ b/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "LicenseApi", - "version": "2026-02-27T15:29:27Z" + "version": "2026-03-27T18:19:52Z" }, "servers": [ { @@ -36,7 +36,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenqza9dE2UnEU1" + "$ref": "#/components/schemas/SandboLicen7ttv4cZS4giU" } } } @@ -73,7 +73,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenABWdja2fpGrf" + "$ref": "#/components/schemas/SandboLicen8c9UvYiiWSov" } } }, @@ -85,7 +85,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -136,7 +136,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenmIdUa45H3yV3" + "$ref": "#/components/schemas/SandboLicenkrLrsMciNA4g" } } } @@ -185,7 +185,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenVzNQc01P5WRr" + "$ref": "#/components/schemas/SandboLicen2Vz3YGPLLiyw" } } } @@ -230,7 +230,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenAZYObIVGD6AE" + "$ref": "#/components/schemas/SandboLicenrIIW1WWuAg11" } } }, @@ -242,7 +242,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -301,7 +301,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicendw4AUcBtsulc" + "$ref": "#/components/schemas/SandboLicenz9o6U9FoduDo" } } } @@ -350,7 +350,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenXTP0xFadIMHH" + "$ref": "#/components/schemas/SandboLicenFmIDl0vIO4Wx" } } }, @@ -362,7 +362,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenQjARLDBg8yqp" + "$ref": "#/components/schemas/SandboLicencx4uEmf1xIGK" } } } @@ -411,7 +411,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicengNz6BQmOzv9N" + "$ref": "#/components/schemas/SandboLicen35ID7rKg6pmg" } } } @@ -474,7 +474,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicen905yAh4VGw9c" + "$ref": "#/components/schemas/SandboLicenbdgqjZHiRCin" } } }, @@ -486,7 +486,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -567,7 +567,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenY31VDvsVuYXJ" + "$ref": "#/components/schemas/SandboLicenTMNnpZtssvOZ" } } }, @@ -579,7 +579,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -652,7 +652,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicennxxmBbSCJcel" + "$ref": "#/components/schemas/SandboLicenSOFKnGm6KsSr" } } }, @@ -664,7 +664,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -745,7 +745,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenTiUhKamH8kWG" + "$ref": "#/components/schemas/SandboLicen1BRGGYZ2H9BZ" } } }, @@ -757,7 +757,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -830,7 +830,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentzGiICqenA1I" + "$ref": "#/components/schemas/SandboLicenGJKqabDhc7zG" } } }, @@ -842,7 +842,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -923,7 +923,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenTdkUw59snX0Q" + "$ref": "#/components/schemas/SandboLicene9LoNzFMzxyp" } } }, @@ -935,7 +935,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1008,7 +1008,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenBxCMDP0yz42u" + "$ref": "#/components/schemas/SandboLicendc4CujpQTISE" } } }, @@ -1020,7 +1020,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1101,7 +1101,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenuVRFe60q6S7D" + "$ref": "#/components/schemas/SandboLicenJUCiAgoCMvNX" } } }, @@ -1113,7 +1113,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1172,7 +1172,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenGJ2Vrxb2wvlG" + "$ref": "#/components/schemas/SandboLicenL9pTEzhVX7rk" } } } @@ -1222,7 +1222,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicengSyqbaS5PyUI" + "$ref": "#/components/schemas/SandboLicen14sZXYfvuEUn" } } } @@ -1261,7 +1261,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenMQ8w3yNRTuci" + "$ref": "#/components/schemas/SandboLicenub1ZBTU9W6qw" } } }, @@ -1280,7 +1280,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenjPULg4TeFeF1" + "$ref": "#/components/schemas/SandboLicenDFkhWUSCFcZm" } } } @@ -1331,7 +1331,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1348,7 +1348,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenjPULg4TeFeF1" + "$ref": "#/components/schemas/SandboLicenDFkhWUSCFcZm" } } } @@ -1397,7 +1397,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1407,7 +1407,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1454,7 +1454,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenTD8eYiNU2b3J" + "$ref": "#/components/schemas/SandboLicenOURP3fzKxUd9" } } }, @@ -1466,7 +1466,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1483,7 +1483,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenjPULg4TeFeF1" + "$ref": "#/components/schemas/SandboLicenDFkhWUSCFcZm" } } } @@ -1534,7 +1534,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1544,7 +1544,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1585,7 +1585,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenxdosUrB9q9s6" + "$ref": "#/components/schemas/SandboLicencffN3I5vrayp" } } }, @@ -1597,7 +1597,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenVVd6s0tk4Osi" + "$ref": "#/components/schemas/SandboLicens761O5xFOa9i" } } } @@ -1623,7 +1623,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenmIdUa45H3yV3" + "$ref": "#/components/schemas/SandboLicenkrLrsMciNA4g" } } } @@ -1647,7 +1647,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenXTP0xFadIMHH" + "$ref": "#/components/schemas/SandboLicenFmIDl0vIO4Wx" } } }, @@ -1659,7 +1659,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenMplIbIWayHWa" + "$ref": "#/components/schemas/SandboLicen27qpKUeWihE2" } } } @@ -1693,7 +1693,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicen7muYupt1OyB4" + "$ref": "#/components/schemas/SandboLicenDor5iRpVkAJb" } } } @@ -1718,7 +1718,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenPUwIzAMSlfRh" + "$ref": "#/components/schemas/SandboLicenNqOvNMkAA7cK" } } } @@ -1734,7 +1734,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1751,7 +1751,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenjPULg4TeFeF1" + "$ref": "#/components/schemas/SandboLicenDFkhWUSCFcZm" } } } @@ -1770,7 +1770,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenMcATit6vegoa" + "$ref": "#/components/schemas/SandboLicenUZbApOOB9TTq" } } }, @@ -1782,7 +1782,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicentIcqTWOgUIGm" + "$ref": "#/components/schemas/SandboLicenoUuAvkbDI3RY" } } } @@ -1799,7 +1799,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboLicenjPULg4TeFeF1" + "$ref": "#/components/schemas/SandboLicenDFkhWUSCFcZm" } } } @@ -1817,54 +1817,125 @@ }, "components": { "schemas": { - "SandboLicenBxCMDP0yz42u": { + "SandboLicenDFkhWUSCFcZm": { + "required": [ + "attributes", + "permissions", + "status", + "userId" + ], "type": "object", - "properties": {} + "properties": { + "permissions": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "actions": { + "type": "object", + "properties": { + "readPrivate": { + "type": "boolean" + }, + "admin": { + "type": "boolean" + }, + "readSSN": { + "type": "boolean" + } + } + }, + "jurisdictions": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "actions": { + "type": "object", + "properties": { + "readPrivate": { + "type": "boolean" + }, + "admin": { + "type": "boolean" + }, + "write": { + "type": "boolean" + }, + "readSSN": { + "type": "boolean" + } + }, + "additionalProperties": false + } + } + } + } + }, + "additionalProperties": false + } + }, + "attributes": { + "required": [ + "email", + "familyName", + "givenName" + ], + "type": "object", + "properties": { + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "email": { + "maxLength": 100, + "minLength": 5, + "type": "string" + } + }, + "additionalProperties": false + }, + "userId": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + } + }, + "additionalProperties": false }, - "SandboLicen7muYupt1OyB4": { + "SandboLicen8c9UvYiiWSov": { "required": [ - "compact", - "dateOfUpdate", - "familyName", - "givenName", - "licenseJurisdiction", - "providerId", - "type" + "compactAdverseActionsNotificationEmails", + "compactOperationsTeamEmails", + "configuredStates", + "licenseeRegistrationEnabled" ], "type": "object", "properties": { - "privileges": { + "configuredStates": { "type": "array", + "description": "List of states that have submitted configurations and their live status", "items": { "required": [ - "administratorSetStatus", - "compact", - "dateOfExpiration", - "jurisdiction", - "licenseJurisdiction", - "licenseType", - "providerId", - "status", - "type" + "isLive", + "postalAbbreviation" ], "type": "object", "properties": { - "licenseType": { - "type": "string", - "enum": [ - "cosmetologist", - "esthetician" - ] - }, - "administratorSetStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "licenseJurisdiction": { + "postalAbbreviation": { "type": "string", + "description": "The postal abbreviation of the jurisdiction", "enum": [ "al", "az", @@ -1878,350 +1949,70 @@ "wa" ] }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "history": { - "type": "array", - "items": { - "required": [ - "compact", - "dateOfUpdate", - "jurisdiction", - "licenseType", - "previous", - "providerId", - "type", - "updateType", - "updatedValues" - ], - "type": "object", - "properties": { - "licenseType": { - "type": "string", - "enum": [ - "cosmetologist", - "esthetician" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "previous": { - "required": [ - "administratorSetStatus", - "dateOfExpiration", - "licenseJurisdiction" - ], - "type": "object", - "properties": { - "administratorSetStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - } - } - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "updatedValues": { - "type": "object", - "properties": { - "administratorSetStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - } - } - }, - "type": { - "type": "string", - "enum": [ - "privilegeUpdate" - ] - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" - }, - "updateType": { - "type": "string", - "enum": [ - "deactivation", - "expiration", - "issuance", - "other", - "renewal", - "encumbrance", - "lifting_encumbrance", - "licenseDeactivation" - ] - } - } - } - }, - "type": { - "type": "string", - "enum": [ - "privilege" - ] - }, - "adverseActions": { - "type": "array", - "items": { - "required": [ - "actionAgainst", - "adverseActionId", - "compact", - "creationDate", - "dateOfUpdate", - "effectiveStartDate", - "jurisdiction", - "licenseType", - "licenseTypeAbbreviation", - "providerId", - "type" - ], - "type": "object", - "properties": { - "licenseType": { - "type": "string" - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "effectiveStartDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseTypeAbbreviation": { - "type": "string" - }, - "adverseActionId": { - "type": "string" - }, - "effectiveLiftDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "type": { - "type": "string", - "enum": [ - "adverseAction" - ] - }, - "creationDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "actionAgainst": { - "type": "string" - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" - } - } - } - }, - "status": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - } - } - } - }, - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "middleName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "provider" - ] - }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" - } - } - }, - "SandboLicenxdosUrB9q9s6": { - "type": "object", - "properties": { - "context": { - "type": "object", - "properties": { - "userId": { - "maxLength": 100, - "minLength": 1, - "type": "string", - "description": "Optional user ID for feature flag evaluation" - }, - "customAttributes": { - "type": "object", - "additionalProperties": { + "isLive": { + "type": "boolean", + "description": "Whether the state is live and available for registrations." + } + }, + "additionalProperties": false + } + }, + "compactAdverseActionsNotificationEmails": { + "maxItems": 10, + "minItems": 1, + "uniqueItems": true, + "type": "array", + "description": "List of email addresses for adverse actions notifications", + "items": { + "type": "string", + "format": "email" + } + }, + "licenseeRegistrationEnabled": { + "type": "boolean", + "description": "Denotes whether licensee registration is enabled" + }, + "compactOperationsTeamEmails": { + "maxItems": 10, + "minItems": 1, + "uniqueItems": true, + "type": "array", + "description": "List of email addresses for operations team notifications", + "items": { + "type": "string", + "format": "email" + } + } + }, + "additionalProperties": false + }, + "SandboLicenoUuAvkbDI3RY": { + "required": [ + "message" + ], + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A message about the request" + } + } + }, + "SandboLicencffN3I5vrayp": { + "type": "object", + "properties": { + "context": { + "type": "object", + "properties": { + "userId": { + "maxLength": 100, + "minLength": 1, + "type": "string", + "description": "Optional user ID for feature flag evaluation" + }, + "customAttributes": { + "type": "object", + "additionalProperties": { "type": "string" }, "description": "Optional custom attributes for feature flag evaluation" @@ -2233,7 +2024,7 @@ }, "additionalProperties": false }, - "SandboLicenXTP0xFadIMHH": { + "SandboLicenFmIDl0vIO4Wx": { "required": [ "query" ], @@ -2288,6 +2079,12 @@ "maxLength": 100, "type": "string", "description": "Filter for providers with a family name" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string", + "description": "Filter for licenses with a specific license number" } }, "additionalProperties": false, @@ -2321,33 +2118,7 @@ }, "additionalProperties": false }, - "SandboLicendw4AUcBtsulc": { - "required": [ - "upload" - ], - "type": "object", - "properties": { - "upload": { - "required": [ - "fields", - "url" - ], - "type": "object", - "properties": { - "fields": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "url": { - "type": "string" - } - } - } - } - }, - "SandboLicenQjARLDBg8yqp": { + "SandboLicen27qpKUeWihE2": { "required": [ "pagination", "providers" @@ -2374,6 +2145,48 @@ } } }, + "query": { + "type": "object", + "properties": { + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string", + "description": "Internal UUID for the provider" + }, + "jurisdiction": { + "type": "string", + "description": "Filter for providers with privilege/license in a jurisdiction", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "givenName": { + "maxLength": 100, + "type": "string", + "description": "Filter for providers with a given name" + }, + "familyName": { + "maxLength": 100, + "type": "string", + "description": "Filter for providers with a family name" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string", + "description": "Filter for licenses with a specific license number" + } + } + }, "sorting": { "required": [ "key" @@ -2404,22 +2217,20 @@ "type": "array", "items": { "required": [ - "birthMonthDay", "compact", - "compactEligibility", - "dateOfExpiration", - "dateOfUpdate", "familyName", "givenName", - "jurisdictionUploadedCompactEligibility", - "jurisdictionUploadedLicenseStatus", "licenseJurisdiction", - "licenseStatus", - "providerId", - "type" + "licenseNumber", + "licenseType", + "providerId" ], "type": "object", "properties": { + "licenseType": { + "type": "string", + "description": "License type or profession designation for this license row" + }, "licenseJurisdiction": { "type": "string", "enum": [ @@ -2427,107 +2238,97 @@ "az", "co", "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "compactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "jurisdictionUploadedCompactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "dateOfBirth": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "jurisdictionUploadedLicenseStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "type": { - "type": "string", - "enum": [ - "provider" - ] - }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "ssnLastFour": { - "pattern": "^[0-9]{4}$", - "type": "string" + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "compact": { "type": "string", - "format": "date" + "enum": [ + "cosm" + ] }, "providerId": { "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", "type": "string" }, - "licenseStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" }, "familyName": { "maxLength": 100, "minLength": 1, "type": "string" }, - "middleName": { + "licenseNumber": { "maxLength": 100, "minLength": 1, "type": "string" - }, - "birthMonthDay": { - "pattern": "^[01]{1}[0-9]{1}-[0-3]{1}[0-9]{1}$", - "type": "string", - "format": "date" - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" } } } } } }, - "SandboLicenVzNQc01P5WRr": { + "SandboLicene9LoNzFMzxyp": { + "required": [ + "effectiveLiftDate" + ], + "type": "object", + "properties": { + "effectiveLiftDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "description": "The effective date when the encumbrance will be lifted", + "format": "date" + } + }, + "additionalProperties": false + }, + "SandboLicenrIIW1WWuAg11": { + "required": [ + "jurisdictionAdverseActionsNotificationEmails", + "jurisdictionOperationsTeamEmails", + "licenseeRegistrationEnabled" + ], + "type": "object", + "properties": { + "jurisdictionAdverseActionsNotificationEmails": { + "maxItems": 10, + "minItems": 1, + "uniqueItems": true, + "type": "array", + "description": "List of email addresses for adverse actions notifications", + "items": { + "type": "string", + "format": "email" + } + }, + "jurisdictionOperationsTeamEmails": { + "maxItems": 10, + "minItems": 1, + "uniqueItems": true, + "type": "array", + "description": "List of email addresses for operations team notifications", + "items": { + "type": "string", + "format": "email" + } + }, + "licenseeRegistrationEnabled": { + "type": "boolean", + "description": "Denotes whether licensee registration is enabled" + } + }, + "additionalProperties": false + }, + "SandboLicen2Vz3YGPLLiyw": { "required": [ "compact", "jurisdictionAdverseActionsNotificationEmails", @@ -2575,259 +2376,270 @@ } } }, - "SandboLicenMcATit6vegoa": { + "SandboLicenDor5iRpVkAJb": { + "required": [ + "compact", + "dateOfUpdate", + "familyName", + "givenName", + "licenseJurisdiction", + "providerId", + "type" + ], "type": "object", "properties": { - "attributes": { - "type": "object", - "properties": { - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" + "privileges": { + "type": "array", + "items": { + "required": [ + "administratorSetStatus", + "compact", + "dateOfExpiration", + "jurisdiction", + "licenseJurisdiction", + "licenseType", + "providerId", + "status", + "type" + ], + "type": "object", + "properties": { + "licenseType": { + "type": "string", + "enum": [ + "cosmetologist", + "esthetician" + ] + }, + "administratorSetStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "licenseJurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "compact": { + "type": "string", + "enum": [ + "cosm" + ] + }, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" + }, + "jurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "type": { + "type": "string", + "enum": [ + "privilege" + ] + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + } + } + } + }, + "licenses": { + "type": "array", + "description": "Sanitized home-state license rows (LicensePublicResponseSchema)", + "items": { + "required": [ + "compact", + "compactEligibility", + "dateOfExpiration", + "jurisdiction", + "licenseNumber", + "licenseStatus", + "licenseType", + "type" + ], + "type": "object", + "properties": { + "licenseType": { + "type": "string", + "enum": [ + "cosmetologist", + "esthetician" + ] + }, + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "compact": { + "type": "string", + "enum": [ + "cosm" + ] + }, + "licenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "jurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "compactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "license" + ] + } } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "SandboLicenuVRFe60q6S7D": { - "required": [ - "action" - ], - "type": "object", - "properties": { - "action": { + } + }, + "licenseJurisdiction": { "type": "string", "enum": [ - "close" + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" ] }, - "encumbrance": { - "required": [ - "clinicalPrivilegeActionCategories", - "encumbranceEffectiveDate", - "encumbranceType" - ], - "type": "object", - "properties": { - "encumbranceEffectiveDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "description": "The effective date of the encumbrance", - "format": "date" - }, - "clinicalPrivilegeActionCategories": { - "type": "array", - "description": "The categories of clinical privilege action", - "items": { - "type": "string" - } - }, - "encumbranceType": { - "type": "string", - "description": "The type of encumbrance", - "enum": [ - "fine", - "reprimand", - "required supervision", - "completion of continuing education", - "public reprimand", - "probation", - "injunctive action", - "suspension", - "revocation", - "denial", - "surrender of license", - "modification of previous action-extension", - "modification of previous action-reduction", - "other monitoring", - "other adjudicated action not listed" - ] - } - }, - "additionalProperties": false, - "description": "Encumbrance data to create" - } - } - }, - "SandboLicenTdkUw59snX0Q": { - "required": [ - "effectiveLiftDate" - ], - "type": "object", - "properties": { - "effectiveLiftDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "description": "The effective date when the encumbrance will be lifted", - "format": "date" - } - }, - "additionalProperties": false - }, - "SandboLicenTiUhKamH8kWG": { - "required": [ - "action" - ], - "type": "object", - "properties": { - "action": { + "compact": { "type": "string", "enum": [ - "close" + "cosm" ] }, - "encumbrance": { - "required": [ - "clinicalPrivilegeActionCategories", - "encumbranceEffectiveDate", - "encumbranceType" - ], - "type": "object", - "properties": { - "encumbranceEffectiveDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "description": "The effective date of the encumbrance", - "format": "date" - }, - "clinicalPrivilegeActionCategories": { - "type": "array", - "description": "The categories of clinical privilege action", - "items": { - "type": "string" - } - }, - "encumbranceType": { - "type": "string", - "description": "The type of encumbrance", - "enum": [ - "fine", - "reprimand", - "required supervision", - "completion of continuing education", - "public reprimand", - "probation", - "injunctive action", - "suspension", - "revocation", - "denial", - "surrender of license", - "modification of previous action-extension", - "modification of previous action-reduction", - "other monitoring", - "other adjudicated action not listed" - ] - } - }, - "additionalProperties": false, - "description": "Encumbrance data to create" - } - } - }, - "SandboLicenAZYObIVGD6AE": { - "required": [ - "jurisdictionAdverseActionsNotificationEmails", - "jurisdictionOperationsTeamEmails", - "licenseeRegistrationEnabled" - ], - "type": "object", - "properties": { - "jurisdictionAdverseActionsNotificationEmails": { - "maxItems": 10, - "minItems": 1, - "uniqueItems": true, - "type": "array", - "description": "List of email addresses for adverse actions notifications", - "items": { - "type": "string", - "format": "email" - } + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" }, - "jurisdictionOperationsTeamEmails": { - "maxItems": 10, - "minItems": 1, - "uniqueItems": true, - "type": "array", - "description": "List of email addresses for operations team notifications", - "items": { - "type": "string", - "format": "email" - } + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" }, - "licenseeRegistrationEnabled": { - "type": "boolean", - "description": "Denotes whether licensee registration is enabled" - } - }, - "additionalProperties": false - }, - "SandboLicen905yAh4VGw9c": { - "required": [ - "clinicalPrivilegeActionCategories", - "encumbranceEffectiveDate", - "encumbranceType" - ], - "type": "object", - "properties": { - "encumbranceEffectiveDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "description": "The effective date of the encumbrance", - "format": "date" + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" }, - "clinicalPrivilegeActionCategories": { - "type": "array", - "description": "The categories of clinical privilege action", - "items": { - "type": "string" - } + "middleName": { + "maxLength": 100, + "minLength": 1, + "type": "string" }, - "encumbranceType": { + "type": { "type": "string", - "description": "The type of encumbrance", "enum": [ - "fine", - "reprimand", - "required supervision", - "completion of continuing education", - "public reprimand", - "probation", - "injunctive action", - "suspension", - "revocation", - "denial", - "surrender of license", - "modification of previous action-extension", - "modification of previous action-reduction", - "other monitoring", - "other adjudicated action not listed" + "provider" ] - } - }, - "additionalProperties": false, - "description": "Encumbrance data to create" + }, + "suffix": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "dateOfUpdate": { + "type": "string", + "format": "date-time" + } + } }, - "SandboLicenVVd6s0tk4Osi": { - "required": [ - "enabled" - ], + "SandboLicenUZbApOOB9TTq": { "type": "object", "properties": { - "enabled": { - "type": "boolean", - "description": "Whether the feature flag is enabled" + "attributes": { + "type": "object", + "properties": { + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false } - } + }, + "additionalProperties": false }, - "SandboLicengSyqbaS5PyUI": { + "SandboLicencx4uEmf1xIGK": { + "required": [ + "pagination", + "providers" + ], "type": "object", "properties": { "pagination": { @@ -2850,127 +2662,160 @@ } } }, - "users": { + "sorting": { + "required": [ + "key" + ], + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "The key to sort results by", + "enum": [ + "dateOfUpdate", + "familyName" + ] + }, + "direction": { + "type": "string", + "description": "Direction to sort results by", + "enum": [ + "ascending", + "descending" + ] + } + }, + "description": "How to sort results" + }, + "providers": { + "maxLength": 100, "type": "array", "items": { "required": [ - "attributes", - "permissions", - "status", - "userId" + "birthMonthDay", + "compact", + "compactEligibility", + "dateOfExpiration", + "dateOfUpdate", + "familyName", + "givenName", + "jurisdictionUploadedCompactEligibility", + "jurisdictionUploadedLicenseStatus", + "licenseJurisdiction", + "licenseStatus", + "providerId", + "type" ], "type": "object", "properties": { - "permissions": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "actions": { - "type": "object", - "properties": { - "readPrivate": { - "type": "boolean" - }, - "admin": { - "type": "boolean" - }, - "readSSN": { - "type": "boolean" - } - } - }, - "jurisdictions": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "actions": { - "type": "object", - "properties": { - "readPrivate": { - "type": "boolean" - }, - "admin": { - "type": "boolean" - }, - "write": { - "type": "boolean" - }, - "readSSN": { - "type": "boolean" - } - }, - "additionalProperties": false - } - } - } - } - }, - "additionalProperties": false - } + "licenseJurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] }, - "attributes": { - "required": [ - "email", - "familyName", - "givenName" - ], - "type": "object", - "properties": { - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "email": { - "maxLength": 100, - "minLength": 5, - "type": "string" - } - }, - "additionalProperties": false + "compact": { + "type": "string", + "enum": [ + "cosm" + ] }, - "userId": { + "givenName": { + "maxLength": 100, + "minLength": 1, "type": "string" }, - "status": { + "compactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "jurisdictionUploadedCompactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "dateOfBirth": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "jurisdictionUploadedLicenseStatus": { "type": "string", "enum": [ "active", "inactive" ] - } - }, - "additionalProperties": false - } - } - }, - "additionalProperties": false - }, - "SandboLicenGJ2Vrxb2wvlG": { - "required": [ - "ssn" - ], - "type": "object", - "properties": { - "ssn": { - "pattern": "^[0-9]{3}-[0-9]{2}-[0-9]{4}$", - "type": "string", - "description": "The provider's social security number" + }, + "type": { + "type": "string", + "enum": [ + "provider" + ] + }, + "suffix": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "ssnLastFour": { + "pattern": "^[0-9]{4}$", + "type": "string" + }, + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" + }, + "licenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "middleName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "birthMonthDay": { + "pattern": "^[01]{1}[0-9]{1}-[0-3]{1}[0-9]{1}$", + "type": "string", + "format": "date" + }, + "dateOfUpdate": { + "type": "string", + "format": "date-time" + } + } + } } } }, - "SandboLicenMQ8w3yNRTuci": { - "required": [ - "attributes", - "permissions" - ], + "SandboLicenOURP3fzKxUd9": { "type": "object", "properties": { "permissions": { @@ -3021,546 +2866,498 @@ }, "additionalProperties": false } - }, - "attributes": { - "required": [ - "email", - "familyName", - "givenName" - ], - "type": "object", - "properties": { - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "email": { - "maxLength": 100, - "minLength": 5, - "type": "string" - } - }, - "additionalProperties": false } }, "additionalProperties": false }, - "SandboLicengNz6BQmOzv9N": { + "SandboLicenkrLrsMciNA4g": { + "type": "array", + "items": { + "required": [ + "compact", + "jurisdictionName", + "postalAbbreviation" + ], + "type": "object", + "properties": { + "postalAbbreviation": { + "type": "string", + "description": "The postal abbreviation of the jurisdiction" + }, + "compact": { + "type": "string" + }, + "jurisdictionName": { + "type": "string", + "description": "The name of the jurisdiction" + } + } + } + }, + "SandboLicenJUCiAgoCMvNX": { "required": [ - "birthMonthDay", - "compact", - "dateOfExpiration", - "dateOfUpdate", - "familyName", - "givenName", - "licenseJurisdiction", - "licenses", - "privileges", - "providerId", - "type" + "action" ], "type": "object", "properties": { - "privileges": { - "type": "array", - "items": { - "required": [ - "administratorSetStatus", - "compact", - "compactTransactionId", - "dateOfExpiration", - "history", - "jurisdiction", - "licenseJurisdiction", - "licenseType", - "providerId", - "status", - "type" - ], - "type": "object", - "properties": { - "investigationStatus": { - "type": "string", - "description": "Status indicating if the privilege is under investigation", - "enum": [ - "underInvestigation" - ] - }, - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "investigations": { - "type": "array", - "items": { - "required": [ - "compact", - "creationDate", - "dateOfUpdate", - "investigationId", - "jurisdiction", - "licenseType", - "providerId", - "submittingUser", - "type" - ], - "type": "object", - "properties": { - "licenseType": { - "type": "string" - }, - "investigationId": { - "type": "string" - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "submittingUser": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "investigation" - ] - }, - "creationDate": { - "type": "string", - "format": "date-time" - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" - } - } - } - }, - "history": { - "type": "array", - "items": { - "required": [ - "compact", - "dateOfUpdate", - "jurisdiction", - "previous", - "type", - "updateType" - ], + "action": { + "type": "string", + "enum": [ + "close" + ] + }, + "encumbrance": { + "required": [ + "clinicalPrivilegeActionCategories", + "encumbranceEffectiveDate", + "encumbranceType" + ], + "type": "object", + "properties": { + "encumbranceEffectiveDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "description": "The effective date of the encumbrance", + "format": "date" + }, + "clinicalPrivilegeActionCategories": { + "type": "array", + "description": "The categories of clinical privilege action", + "items": { + "type": "string" + } + }, + "encumbranceType": { + "type": "string", + "description": "The type of encumbrance", + "enum": [ + "fine", + "reprimand", + "required supervision", + "completion of continuing education", + "public reprimand", + "probation", + "injunctive action", + "suspension", + "revocation", + "denial", + "surrender of license", + "modification of previous action-extension", + "modification of previous action-reduction", + "other monitoring", + "other adjudicated action not listed" + ] + } + }, + "additionalProperties": false, + "description": "Encumbrance data to create" + } + } + }, + "SandboLicenTMNnpZtssvOZ": { + "required": [ + "effectiveLiftDate" + ], + "type": "object", + "properties": { + "effectiveLiftDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "description": "The effective date when the encumbrance will be lifted", + "format": "date" + } + }, + "additionalProperties": false + }, + "SandboLicen14sZXYfvuEUn": { + "type": "object", + "properties": { + "pagination": { + "type": "object", + "properties": { + "prevLastKey": { + "maxLength": 1024, + "minLength": 1, + "type": "object" + }, + "lastKey": { + "maxLength": 1024, + "minLength": 1, + "type": "object" + }, + "pageSize": { + "maximum": 100, + "minimum": 5, + "type": "integer" + } + } + }, + "users": { + "type": "array", + "items": { + "required": [ + "attributes", + "permissions", + "status", + "userId" + ], + "type": "object", + "properties": { + "permissions": { + "type": "object", + "additionalProperties": { "type": "object", "properties": { - "removedValues": { - "type": "array", - "description": "List of field names that were present in the previous record but removed in the update", - "items": { - "type": "string" - } - }, - "licenseType": { - "type": "string", - "enum": [ - "cosmetologist", - "esthetician" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "previous": { - "required": [ - "administratorSetStatus", - "compactTransactionId", - "dateOfExpiration", - "licenseJurisdiction" - ], + "actions": { "type": "object", "properties": { - "administratorSetStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "type": { - "type": "string", - "enum": [ - "privilege" - ] + "readPrivate": { + "type": "boolean" }, - "compactTransactionId": { - "type": "string" + "admin": { + "type": "boolean" }, - "status": { - "type": "string", - "enum": [ - "active", - "inactive" - ] + "readSSN": { + "type": "boolean" } } }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "updatedValues": { + "jurisdictions": { "type": "object", - "properties": { - "administratorSetStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "type": { - "type": "string", - "enum": [ - "privilege" - ] - }, - "compactTransactionId": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "active", - "inactive" - ] + "additionalProperties": { + "type": "object", + "properties": { + "actions": { + "type": "object", + "properties": { + "readPrivate": { + "type": "boolean" + }, + "admin": { + "type": "boolean" + }, + "write": { + "type": "boolean" + }, + "readSSN": { + "type": "boolean" + } + }, + "additionalProperties": false + } } } - }, - "type": { - "type": "string", - "enum": [ - "privilegeUpdate" - ] - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" - }, - "updateType": { - "type": "string", - "enum": [ - "deactivation", - "expiration", - "issuance", - "other", - "renewal", - "encumbrance", - "lifting_encumbrance", - "licenseDeactivation" - ] } - } + }, + "additionalProperties": false } }, - "type": { - "type": "string", - "enum": [ - "privilege" - ] + "attributes": { + "required": [ + "email", + "familyName", + "givenName" + ], + "type": "object", + "properties": { + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "email": { + "maxLength": 100, + "minLength": 5, + "type": "string" + } + }, + "additionalProperties": false }, - "compactTransactionId": { + "userId": { "type": "string" }, - "licenseType": { - "type": "string", - "enum": [ - "cosmetologist", - "esthetician" - ] - }, - "administratorSetStatus": { + "status": { "type": "string", "enum": [ "active", "inactive" ] + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + "SandboLicenub1ZBTU9W6qw": { + "required": [ + "attributes", + "permissions" + ], + "type": "object", + "properties": { + "permissions": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "actions": { + "type": "object", + "properties": { + "readPrivate": { + "type": "boolean" + }, + "admin": { + "type": "boolean" + }, + "readSSN": { + "type": "boolean" + } + } }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "adverseActions": { - "type": "array", - "items": { - "required": [ - "actionAgainst", - "adverseActionId", - "compact", - "creationDate", - "dateOfUpdate", - "effectiveStartDate", - "encumbranceType", - "jurisdiction", - "licenseType", - "licenseTypeAbbreviation", - "providerId", - "type" - ], + "jurisdictions": { + "type": "object", + "additionalProperties": { "type": "object", "properties": { - "clinicalPrivilegeActionCategories": { - "type": "array", - "description": "The categories of clinical privilege action", - "items": { - "type": "string" - } - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "jurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "licenseTypeAbbreviation": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "adverseAction" - ] - }, - "creationDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "actionAgainst": { - "type": "string" - }, - "licenseType": { - "type": "string" - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "effectiveStartDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "adverseActionId": { - "type": "string" - }, - "effectiveLiftDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "encumbranceType": { - "type": "string" - }, - "liftingUser": { - "type": "string" - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" + "actions": { + "type": "object", + "properties": { + "readPrivate": { + "type": "boolean" + }, + "admin": { + "type": "boolean" + }, + "write": { + "type": "boolean" + }, + "readSSN": { + "type": "boolean" + } + }, + "additionalProperties": false } } } - }, - "status": { - "type": "string", - "enum": [ - "active", - "inactive" - ] } + }, + "additionalProperties": false + } + }, + "attributes": { + "required": [ + "email", + "familyName", + "givenName" + ], + "type": "object", + "properties": { + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "email": { + "maxLength": 100, + "minLength": 5, + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "SandboLicenL9pTEzhVX7rk": { + "required": [ + "ssn" + ], + "type": "object", + "properties": { + "ssn": { + "pattern": "^[0-9]{3}-[0-9]{2}-[0-9]{4}$", + "type": "string", + "description": "The provider's social security number" + } + } + }, + "SandboLicendc4CujpQTISE": { + "type": "object", + "properties": {} + }, + "SandboLicenSOFKnGm6KsSr": { + "type": "object", + "properties": {} + }, + "SandboLicen1BRGGYZ2H9BZ": { + "required": [ + "action" + ], + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": [ + "close" + ] + }, + "encumbrance": { + "required": [ + "clinicalPrivilegeActionCategories", + "encumbranceEffectiveDate", + "encumbranceType" + ], + "type": "object", + "properties": { + "encumbranceEffectiveDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "description": "The effective date of the encumbrance", + "format": "date" + }, + "clinicalPrivilegeActionCategories": { + "type": "array", + "description": "The categories of clinical privilege action", + "items": { + "type": "string" + } + }, + "encumbranceType": { + "type": "string", + "description": "The type of encumbrance", + "enum": [ + "fine", + "reprimand", + "required supervision", + "completion of continuing education", + "public reprimand", + "probation", + "injunctive action", + "suspension", + "revocation", + "denial", + "surrender of license", + "modification of previous action-extension", + "modification of previous action-reduction", + "other monitoring", + "other adjudicated action not listed" + ] } + }, + "additionalProperties": false, + "description": "Encumbrance data to create" + } + } + }, + "SandboLicenbdgqjZHiRCin": { + "required": [ + "clinicalPrivilegeActionCategories", + "encumbranceEffectiveDate", + "encumbranceType" + ], + "type": "object", + "properties": { + "encumbranceEffectiveDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "description": "The effective date of the encumbrance", + "format": "date" + }, + "clinicalPrivilegeActionCategories": { + "type": "array", + "description": "The categories of clinical privilege action", + "items": { + "type": "string" } }, - "licenseJurisdiction": { + "encumbranceType": { + "type": "string", + "description": "The type of encumbrance", + "enum": [ + "fine", + "reprimand", + "required supervision", + "completion of continuing education", + "public reprimand", + "probation", + "injunctive action", + "suspension", + "revocation", + "denial", + "surrender of license", + "modification of previous action-extension", + "modification of previous action-reduction", + "other monitoring", + "other adjudicated action not listed" + ] + } + }, + "additionalProperties": false, + "description": "Encumbrance data to create" + }, + "SandboLicenGJKqabDhc7zG": { + "required": [ + "clinicalPrivilegeActionCategories", + "encumbranceEffectiveDate", + "encumbranceType" + ], + "type": "object", + "properties": { + "encumbranceEffectiveDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "description": "The effective date of the encumbrance", + "format": "date" + }, + "clinicalPrivilegeActionCategories": { + "type": "array", + "description": "The categories of clinical privilege action", + "items": { + "type": "string" + } + }, + "encumbranceType": { + "type": "string", + "description": "The type of encumbrance", + "enum": [ + "fine", + "reprimand", + "required supervision", + "completion of continuing education", + "public reprimand", + "probation", + "injunctive action", + "suspension", + "revocation", + "denial", + "surrender of license", + "modification of previous action-extension", + "modification of previous action-reduction", + "other monitoring", + "other adjudicated action not listed" + ] + } + }, + "additionalProperties": false, + "description": "Encumbrance data to create" + }, + "SandboLicenNqOvNMkAA7cK": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { "type": "string", "enum": [ "al", @@ -3574,94 +3371,183 @@ "va", "wa" ] + } + } + }, + "SandboLicenz9o6U9FoduDo": { + "required": [ + "upload" + ], + "type": "object", + "properties": { + "upload": { + "required": [ + "fields", + "url" + ], + "type": "object", + "properties": { + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "url": { + "type": "string" + } + } + } + } + }, + "SandboLicens761O5xFOa9i": { + "required": [ + "enabled" + ], + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether the feature flag is enabled" + } + } + }, + "SandboLicen7ttv4cZS4giU": { + "required": [ + "compactAbbr", + "compactAdverseActionsNotificationEmails", + "compactName", + "compactOperationsTeamEmails", + "configuredStates", + "licenseeRegistrationEnabled" + ], + "type": "object", + "properties": { + "configuredStates": { + "type": "array", + "description": "List of states that have submitted configurations and their live status", + "items": { + "required": [ + "isLive", + "postalAbbreviation" + ], + "type": "object", + "properties": { + "postalAbbreviation": { + "type": "string", + "description": "The postal abbreviation of the jurisdiction", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "isLive": { + "type": "boolean", + "description": "Whether the state is live and available for registrations." + } + } + } }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] - }, - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "compactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "jurisdictionUploadedCompactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] + "compactAdverseActionsNotificationEmails": { + "type": "array", + "description": "List of email addresses for adverse actions notifications", + "items": { + "type": "string", + "format": "email" + } }, - "dateOfBirth": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" + "licenseeRegistrationEnabled": { + "type": "boolean", + "description": "Denotes whether licensee registration is enabled" }, - "jurisdictionUploadedLicenseStatus": { + "compactAbbr": { "type": "string", - "enum": [ - "active", - "inactive" - ] + "description": "The abbreviation of the compact" }, - "type": { + "compactName": { "type": "string", - "enum": [ - "provider" - ] - }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" + "description": "The full name of the compact" }, - "licenses": { + "compactOperationsTeamEmails": { + "type": "array", + "description": "List of email addresses for operations team notifications", + "items": { + "type": "string", + "format": "email" + } + } + } + }, + "SandboLicen35ID7rKg6pmg": { + "required": [ + "birthMonthDay", + "compact", + "dateOfExpiration", + "dateOfUpdate", + "familyName", + "givenName", + "licenseJurisdiction", + "licenses", + "privileges", + "providerId", + "type" + ], + "type": "object", + "properties": { + "privileges": { "type": "array", "items": { "required": [ + "administratorSetStatus", "compact", - "compactEligibility", + "compactTransactionId", "dateOfExpiration", - "dateOfIssuance", - "dateOfRenewal", - "dateOfUpdate", - "familyName", - "givenName", "history", - "homeAddressCity", - "homeAddressPostalCode", - "homeAddressState", - "homeAddressStreet1", "jurisdiction", - "jurisdictionUploadedCompactEligibility", - "jurisdictionUploadedLicenseStatus", - "licenseStatus", + "licenseJurisdiction", "licenseType", - "middleName", "providerId", + "status", "type" ], "type": "object", "properties": { + "investigationStatus": { + "type": "string", + "description": "Status indicating if the privilege is under investigation", + "enum": [ + "underInvestigation" + ] + }, + "licenseJurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, "compact": { "type": "string", "enum": [ "cosm" ] }, - "homeAddressStreet2": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, "jurisdiction": { "type": "string", "enum": [ @@ -3677,11 +3563,6 @@ "wa" ] }, - "homeAddressStreet1": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, "investigations": { "type": "array", "items": { @@ -3749,112 +3630,6 @@ } } }, - "type": { - "type": "string", - "enum": [ - "license-home" - ] - }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "dateOfIssuance": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseType": { - "type": "string", - "enum": [ - "cosmetologist", - "esthetician" - ] - }, - "emailAddress": { - "maxLength": 100, - "minLength": 5, - "type": "string", - "format": "email" - }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "homeAddressState": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "dateOfRenewal": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressCity": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, - "licenseNumber": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "investigationStatus": { - "type": "string", - "description": "Status indicating if the license is under investigation", - "enum": [ - "underInvestigation" - ] - }, - "homeAddressPostalCode": { - "maxLength": 7, - "minLength": 5, - "type": "string" - }, - "compactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "jurisdictionUploadedCompactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "dateOfBirth": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "jurisdictionUploadedLicenseStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, "history": { "type": "array", "items": { @@ -3889,134 +3664,81 @@ ] }, "previous": { - "required": [ - "dateOfExpiration", - "dateOfIssuance", - "dateOfRenewal", - "familyName", - "givenName", - "homeAddressCity", - "homeAddressPostalCode", - "homeAddressState", - "homeAddressStreet1", - "jurisdictionUploadedCompactEligibility", - "jurisdictionUploadedLicenseStatus", - "middleName" + "required": [ + "administratorSetStatus", + "compactTransactionId", + "dateOfExpiration", + "licenseJurisdiction" ], "type": "object", "properties": { - "homeAddressStreet2": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressPostalCode": { - "maxLength": 7, - "minLength": 5, - "type": "string" - }, - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressStreet1": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, - "compactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "jurisdictionUploadedCompactEligibility": { + "administratorSetStatus": { "type": "string", "enum": [ - "eligible", - "ineligible" + "active", + "inactive" ] }, - "dateOfBirth": { + "dateOfExpiration": { "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", "type": "string", "format": "date" }, - "jurisdictionUploadedLicenseStatus": { + "licenseJurisdiction": { "type": "string", "enum": [ - "active", - "inactive" + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" ] }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "dateOfIssuance": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "compact": { "type": "string", - "format": "date" + "enum": [ + "cosm" + ] }, - "emailAddress": { - "maxLength": 100, - "minLength": 5, - "type": "string", - "format": "email" + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "jurisdiction": { "type": "string", - "format": "date" + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] }, - "phoneNumber": { - "pattern": "^\\+[0-9]{8,15}$", - "type": "string" + "type": { + "type": "string", + "enum": [ + "privilege" + ] }, - "homeAddressState": { - "maxLength": 100, - "minLength": 2, + "compactTransactionId": { "type": "string" }, - "dateOfRenewal": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "licenseStatus": { + "status": { "type": "string", "enum": [ "active", "inactive" ] - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressCity": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, - "licenseNumber": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "middleName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "licenseStatusName": { - "maxLength": 100, - "minLength": 1, - "type": "string" } } }, @@ -4038,125 +3760,80 @@ "updatedValues": { "type": "object", "properties": { - "homeAddressStreet2": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressPostalCode": { - "maxLength": 7, - "minLength": 5, - "type": "string" - }, - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressStreet1": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, - "compactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "jurisdictionUploadedCompactEligibility": { - "type": "string", - "enum": [ - "eligible", - "ineligible" - ] - }, - "dateOfBirth": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "jurisdictionUploadedLicenseStatus": { + "administratorSetStatus": { "type": "string", "enum": [ "active", "inactive" ] }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "dateOfIssuance": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "emailAddress": { - "maxLength": 100, - "minLength": 5, - "type": "string", - "format": "email" - }, "dateOfExpiration": { "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", "type": "string", "format": "date" }, - "phoneNumber": { - "pattern": "^\\+[0-9]{8,15}$", - "type": "string" - }, - "homeAddressState": { - "maxLength": 100, - "minLength": 2, - "type": "string" - }, - "dateOfRenewal": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "licenseJurisdiction": { "type": "string", - "format": "date" + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] }, - "licenseStatus": { + "compact": { "type": "string", "enum": [ - "active", - "inactive" + "cosm" ] }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "homeAddressCity": { - "maxLength": 100, - "minLength": 2, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", "type": "string" }, - "licenseNumber": { - "maxLength": 100, - "minLength": 1, - "type": "string" + "jurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] }, - "middleName": { - "maxLength": 100, - "minLength": 1, - "type": "string" + "type": { + "type": "string", + "enum": [ + "privilege" + ] }, - "licenseStatusName": { - "maxLength": 100, - "minLength": 1, + "compactTransactionId": { "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive" + ] } } }, "type": { "type": "string", "enum": [ - "licenseUpdate" + "privilegeUpdate" ] }, "dateOfUpdate": { @@ -4179,29 +3856,36 @@ } } }, - "ssnLastFour": { - "pattern": "^[0-9]{4}$", - "type": "string" + "type": { + "type": "string", + "enum": [ + "privilege" + ] }, - "phoneNumber": { - "pattern": "^\\+[0-9]{8,15}$", + "compactTransactionId": { "type": "string" }, - "licenseStatus": { + "licenseType": { + "type": "string", + "enum": [ + "cosmetologist", + "esthetician" + ] + }, + "administratorSetStatus": { "type": "string", "enum": [ "active", "inactive" ] }, - "middleName": { - "maxLength": 100, - "minLength": 1, - "type": "string" + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" }, - "licenseStatusName": { - "maxLength": 100, - "minLength": 1, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", "type": "string" }, "adverseActions": { @@ -4301,59 +3985,17 @@ } } }, - "dateOfUpdate": { + "status": { "type": "string", - "format": "date-time" + "enum": [ + "active", + "inactive" + ] } } } }, - "ssnLastFour": { - "pattern": "^[0-9]{4}$", - "type": "string" - }, - "dateOfExpiration": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string", - "format": "date" - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "licenseStatus": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "middleName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "birthMonthDay": { - "pattern": "^[01]{1}[0-9]{1}-[0-3]{1}[0-9]{1}$", - "type": "string", - "format": "date" - }, - "dateOfUpdate": { - "type": "string", - "format": "date-time" - } - } - }, - "SandboLicenPUwIzAMSlfRh": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { + "licenseJurisdiction": { "type": "string", "enum": [ "al", @@ -4367,151 +4009,96 @@ "va", "wa" ] - } - } - }, - "SandboLicentzGiICqenA1I": { - "required": [ - "clinicalPrivilegeActionCategories", - "encumbranceEffectiveDate", - "encumbranceType" - ], - "type": "object", - "properties": { - "encumbranceEffectiveDate": { - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + }, + "compact": { "type": "string", - "description": "The effective date of the encumbrance", - "format": "date" + "enum": [ + "cosm" + ] }, - "clinicalPrivilegeActionCategories": { - "type": "array", - "description": "The categories of clinical privilege action", - "items": { - "type": "string" - } + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" }, - "encumbranceType": { + "compactEligibility": { "type": "string", - "description": "The type of encumbrance", "enum": [ - "fine", - "reprimand", - "required supervision", - "completion of continuing education", - "public reprimand", - "probation", - "injunctive action", - "suspension", - "revocation", - "denial", - "surrender of license", - "modification of previous action-extension", - "modification of previous action-reduction", - "other monitoring", - "other adjudicated action not listed" + "eligible", + "ineligible" ] - } - }, - "additionalProperties": false, - "description": "Encumbrance data to create" - }, - "SandboLicenqza9dE2UnEU1": { - "required": [ - "compactAbbr", - "compactAdverseActionsNotificationEmails", - "compactName", - "compactOperationsTeamEmails", - "configuredStates", - "licenseeRegistrationEnabled" - ], - "type": "object", - "properties": { - "configuredStates": { - "type": "array", - "description": "List of states that have submitted configurations and their live status", - "items": { - "required": [ - "isLive", - "postalAbbreviation" - ], - "type": "object", - "properties": { - "postalAbbreviation": { - "type": "string", - "description": "The postal abbreviation of the jurisdiction", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "isLive": { - "type": "boolean", - "description": "Whether the state is live and available for registrations." - } - } - } }, - "compactAdverseActionsNotificationEmails": { - "type": "array", - "description": "List of email addresses for adverse actions notifications", - "items": { - "type": "string", - "format": "email" - } + "jurisdictionUploadedCompactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] }, - "licenseeRegistrationEnabled": { - "type": "boolean", - "description": "Denotes whether licensee registration is enabled" + "dateOfBirth": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" }, - "compactAbbr": { + "jurisdictionUploadedLicenseStatus": { "type": "string", - "description": "The abbreviation of the compact" + "enum": [ + "active", + "inactive" + ] }, - "compactName": { + "type": { "type": "string", - "description": "The full name of the compact" + "enum": [ + "provider" + ] }, - "compactOperationsTeamEmails": { - "type": "array", - "description": "List of email addresses for operations team notifications", - "items": { - "type": "string", - "format": "email" - } - } - } - }, - "SandboLicenABWdja2fpGrf": { - "required": [ - "compactAdverseActionsNotificationEmails", - "compactOperationsTeamEmails", - "configuredStates", - "licenseeRegistrationEnabled" - ], - "type": "object", - "properties": { - "configuredStates": { + "suffix": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "licenses": { "type": "array", - "description": "List of states that have submitted configurations and their live status", "items": { "required": [ - "isLive", - "postalAbbreviation" + "compact", + "compactEligibility", + "dateOfExpiration", + "dateOfIssuance", + "dateOfRenewal", + "dateOfUpdate", + "familyName", + "givenName", + "history", + "homeAddressCity", + "homeAddressPostalCode", + "homeAddressState", + "homeAddressStreet1", + "jurisdiction", + "jurisdictionUploadedCompactEligibility", + "jurisdictionUploadedLicenseStatus", + "licenseStatus", + "licenseType", + "middleName", + "providerId", + "type" ], "type": "object", "properties": { - "postalAbbreviation": { + "compact": { + "type": "string", + "enum": [ + "cosm" + ] + }, + "homeAddressStreet2": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "jurisdiction": { "type": "string", - "description": "The postal abbreviation of the jurisdiction", "enum": [ "al", "az", @@ -4525,409 +4112,675 @@ "wa" ] }, - "isLive": { - "type": "boolean", - "description": "Whether the state is live and available for registrations." - } - }, - "additionalProperties": false - } - }, - "compactAdverseActionsNotificationEmails": { - "maxItems": 10, - "minItems": 1, - "uniqueItems": true, - "type": "array", - "description": "List of email addresses for adverse actions notifications", - "items": { - "type": "string", - "format": "email" - } - }, - "licenseeRegistrationEnabled": { - "type": "boolean", - "description": "Denotes whether licensee registration is enabled" - }, - "compactOperationsTeamEmails": { - "maxItems": 10, - "minItems": 1, - "uniqueItems": true, - "type": "array", - "description": "List of email addresses for operations team notifications", - "items": { - "type": "string", - "format": "email" - } - } - }, - "additionalProperties": false - }, - "SandboLicenjPULg4TeFeF1": { - "required": [ - "attributes", - "permissions", - "status", - "userId" - ], - "type": "object", - "properties": { - "permissions": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "actions": { - "type": "object", - "properties": { - "readPrivate": { - "type": "boolean" - }, - "admin": { - "type": "boolean" - }, - "readSSN": { - "type": "boolean" + "homeAddressStreet1": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "investigations": { + "type": "array", + "items": { + "required": [ + "compact", + "creationDate", + "dateOfUpdate", + "investigationId", + "jurisdiction", + "licenseType", + "providerId", + "submittingUser", + "type" + ], + "type": "object", + "properties": { + "licenseType": { + "type": "string" + }, + "investigationId": { + "type": "string" + }, + "compact": { + "type": "string", + "enum": [ + "cosm" + ] + }, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" + }, + "jurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "submittingUser": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "investigation" + ] + }, + "creationDate": { + "type": "string", + "format": "date-time" + }, + "dateOfUpdate": { + "type": "string", + "format": "date-time" + } } } }, - "jurisdictions": { - "type": "object", - "additionalProperties": { + "type": { + "type": "string", + "enum": [ + "license-home" + ] + }, + "suffix": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "dateOfIssuance": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "licenseType": { + "type": "string", + "enum": [ + "cosmetologist", + "esthetician" + ] + }, + "emailAddress": { + "maxLength": 100, + "minLength": 5, + "type": "string", + "format": "email" + }, + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "homeAddressState": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" + }, + "dateOfRenewal": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressCity": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "investigationStatus": { + "type": "string", + "description": "Status indicating if the license is under investigation", + "enum": [ + "underInvestigation" + ] + }, + "homeAddressPostalCode": { + "maxLength": 7, + "minLength": 5, + "type": "string" + }, + "compactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "jurisdictionUploadedCompactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "dateOfBirth": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "jurisdictionUploadedLicenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "history": { + "type": "array", + "items": { + "required": [ + "compact", + "dateOfUpdate", + "jurisdiction", + "previous", + "type", + "updateType" + ], "type": "object", "properties": { - "actions": { + "removedValues": { + "type": "array", + "description": "List of field names that were present in the previous record but removed in the update", + "items": { + "type": "string" + } + }, + "licenseType": { + "type": "string", + "enum": [ + "cosmetologist", + "esthetician" + ] + }, + "compact": { + "type": "string", + "enum": [ + "cosm" + ] + }, + "previous": { + "required": [ + "dateOfExpiration", + "dateOfIssuance", + "dateOfRenewal", + "familyName", + "givenName", + "homeAddressCity", + "homeAddressPostalCode", + "homeAddressState", + "homeAddressStreet1", + "jurisdictionUploadedCompactEligibility", + "jurisdictionUploadedLicenseStatus", + "middleName" + ], "type": "object", "properties": { - "readPrivate": { - "type": "boolean" + "homeAddressStreet2": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressPostalCode": { + "maxLength": 7, + "minLength": 5, + "type": "string" + }, + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressStreet1": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "compactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "jurisdictionUploadedCompactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "dateOfBirth": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "jurisdictionUploadedLicenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "suffix": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "dateOfIssuance": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "emailAddress": { + "maxLength": 100, + "minLength": 5, + "type": "string", + "format": "email" + }, + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "phoneNumber": { + "pattern": "^\\+[0-9]{8,15}$", + "type": "string" + }, + "homeAddressState": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "dateOfRenewal": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "licenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressCity": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "middleName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "licenseStatusName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + } + } + }, + "jurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "updatedValues": { + "type": "object", + "properties": { + "homeAddressStreet2": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressPostalCode": { + "maxLength": 7, + "minLength": 5, + "type": "string" + }, + "givenName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressStreet1": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "compactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "jurisdictionUploadedCompactEligibility": { + "type": "string", + "enum": [ + "eligible", + "ineligible" + ] + }, + "dateOfBirth": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "jurisdictionUploadedLicenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "suffix": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "dateOfIssuance": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" }, - "admin": { - "type": "boolean" + "emailAddress": { + "maxLength": 100, + "minLength": 5, + "type": "string", + "format": "email" }, - "write": { - "type": "boolean" + "dateOfExpiration": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" }, - "readSSN": { - "type": "boolean" + "phoneNumber": { + "pattern": "^\\+[0-9]{8,15}$", + "type": "string" + }, + "homeAddressState": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "dateOfRenewal": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "licenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "homeAddressCity": { + "maxLength": 100, + "minLength": 2, + "type": "string" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "middleName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "licenseStatusName": { + "maxLength": 100, + "minLength": 1, + "type": "string" } - }, - "additionalProperties": false + } + }, + "type": { + "type": "string", + "enum": [ + "licenseUpdate" + ] + }, + "dateOfUpdate": { + "type": "string", + "format": "date-time" + }, + "updateType": { + "type": "string", + "enum": [ + "deactivation", + "expiration", + "issuance", + "other", + "renewal", + "encumbrance", + "lifting_encumbrance", + "licenseDeactivation" + ] } } } - } - }, - "additionalProperties": false - } - }, - "attributes": { - "required": [ - "email", - "familyName", - "givenName" - ], - "type": "object", - "properties": { - "givenName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "email": { - "maxLength": 100, - "minLength": 5, - "type": "string" - } - }, - "additionalProperties": false - }, - "userId": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - } - }, - "additionalProperties": false - }, - "SandboLicenMplIbIWayHWa": { - "required": [ - "pagination", - "providers" - ], - "type": "object", - "properties": { - "pagination": { - "type": "object", - "properties": { - "prevLastKey": { - "maxLength": 1024, - "minLength": 1, - "type": "object" - }, - "lastKey": { - "maxLength": 1024, - "minLength": 1, - "type": "object" - }, - "pageSize": { - "maximum": 100, - "minimum": 5, - "type": "integer" - } - } - }, - "query": { - "type": "object", - "properties": { - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string", - "description": "Internal UUID for the provider" - }, - "jurisdiction": { - "type": "string", - "description": "Filter for providers with privilege/license in a jurisdiction", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "givenName": { - "maxLength": 100, - "type": "string", - "description": "Filter for providers with a given name" - }, - "familyName": { - "maxLength": 100, - "type": "string", - "description": "Filter for providers with a family name" - } - } - }, - "sorting": { - "required": [ - "key" - ], - "type": "object", - "properties": { - "key": { - "type": "string", - "description": "The key to sort results by", - "enum": [ - "dateOfUpdate", - "familyName" - ] - }, - "direction": { - "type": "string", - "description": "Direction to sort results by", - "enum": [ - "ascending", - "descending" - ] - } - }, - "description": "How to sort results" - }, - "providers": { - "maxLength": 100, - "type": "array", - "items": { - "required": [ - "compact", - "familyName", - "givenName", - "licenseJurisdiction", - "providerId", - "type" - ], - "type": "object", - "properties": { - "licenseJurisdiction": { - "type": "string", - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ] - }, - "compact": { - "type": "string", - "enum": [ - "cosm" - ] }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "ssnLastFour": { + "pattern": "^[0-9]{4}$", "type": "string" }, - "givenName": { - "maxLength": 100, - "minLength": 1, + "phoneNumber": { + "pattern": "^\\+[0-9]{8,15}$", "type": "string" }, - "familyName": { - "maxLength": 100, - "minLength": 1, - "type": "string" + "licenseStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ] }, "middleName": { "maxLength": 100, "minLength": 1, "type": "string" }, - "type": { - "type": "string", - "enum": [ - "provider" - ] - }, - "suffix": { + "licenseStatusName": { "maxLength": 100, "minLength": 1, "type": "string" }, + "adverseActions": { + "type": "array", + "items": { + "required": [ + "actionAgainst", + "adverseActionId", + "compact", + "creationDate", + "dateOfUpdate", + "effectiveStartDate", + "encumbranceType", + "jurisdiction", + "licenseType", + "licenseTypeAbbreviation", + "providerId", + "type" + ], + "type": "object", + "properties": { + "clinicalPrivilegeActionCategories": { + "type": "array", + "description": "The categories of clinical privilege action", + "items": { + "type": "string" + } + }, + "compact": { + "type": "string", + "enum": [ + "cosm" + ] + }, + "jurisdiction": { + "type": "string", + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ] + }, + "licenseTypeAbbreviation": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "adverseAction" + ] + }, + "creationDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "actionAgainst": { + "type": "string" + }, + "licenseType": { + "type": "string" + }, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" + }, + "effectiveStartDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "adverseActionId": { + "type": "string" + }, + "effectiveLiftDate": { + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string", + "format": "date" + }, + "encumbranceType": { + "type": "string" + }, + "liftingUser": { + "type": "string" + }, + "dateOfUpdate": { + "type": "string", + "format": "date-time" + } + } + } + }, "dateOfUpdate": { "type": "string", "format": "date-time" } } } - } - } - }, - "SandboLicennxxmBbSCJcel": { - "type": "object", - "properties": {} - }, - "SandboLicenY31VDvsVuYXJ": { - "required": [ - "effectiveLiftDate" - ], - "type": "object", - "properties": { - "effectiveLiftDate": { + }, + "ssnLastFour": { + "pattern": "^[0-9]{4}$", + "type": "string" + }, + "dateOfExpiration": { "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", "type": "string", - "description": "The effective date when the encumbrance will be lifted", "format": "date" - } - }, - "additionalProperties": false - }, - "SandboLicenmIdUa45H3yV3": { - "type": "array", - "items": { - "required": [ - "compact", - "jurisdictionName", - "postalAbbreviation" - ], - "type": "object", - "properties": { - "postalAbbreviation": { - "type": "string", - "description": "The postal abbreviation of the jurisdiction" - }, - "compact": { - "type": "string" - }, - "jurisdictionName": { - "type": "string", - "description": "The name of the jurisdiction" - } - } - } - }, - "SandboLicenTD8eYiNU2b3J": { - "type": "object", - "properties": { - "permissions": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "actions": { - "type": "object", - "properties": { - "readPrivate": { - "type": "boolean" - }, - "admin": { - "type": "boolean" - }, - "readSSN": { - "type": "boolean" - } - } - }, - "jurisdictions": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "actions": { - "type": "object", - "properties": { - "readPrivate": { - "type": "boolean" - }, - "admin": { - "type": "boolean" - }, - "write": { - "type": "boolean" - }, - "readSSN": { - "type": "boolean" - } - }, - "additionalProperties": false - } - } - } - } - }, - "additionalProperties": false - } - } - }, - "additionalProperties": false - }, - "SandboLicentIcqTWOgUIGm": { - "required": [ - "message" - ], - "type": "object", - "properties": { - "message": { + }, + "providerId": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", + "type": "string" + }, + "licenseStatus": { "type": "string", - "description": "A message about the request" + "enum": [ + "active", + "inactive" + ] + }, + "familyName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "middleName": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "birthMonthDay": { + "pattern": "^[01]{1}[0-9]{1}-[0-3]{1}[0-9]{1}$", + "type": "string", + "format": "date" + }, + "dateOfUpdate": { + "type": "string", + "format": "date-time" } } } diff --git a/backend/cosmetology-app/docs/internal/postman/postman-collection.json b/backend/cosmetology-app/docs/internal/postman/postman-collection.json index 006731546..d341d00df 100644 --- a/backend/cosmetology-app/docs/internal/postman/postman-collection.json +++ b/backend/cosmetology-app/docs/internal/postman/postman-collection.json @@ -10,7 +10,7 @@ "type": "bearer" }, "info": { - "_postman_id": "c86d356c-40cb-4d66-9540-42f3202343d5", + "_postman_id": "3ce93373-3ce2-4b76-bcdc-fd6651c792a5", "description": { "content": "", "type": "text/plain" @@ -401,7 +401,7 @@ "item": [ { "event": [], - "id": "69ea0609-73d9-4dbc-8c37-70535531091a", + "id": "17eccb36-a50d-4dae-bd76-b64ccccaff34", "name": "/v1/compacts/:compact", "protocolProfileBehavior": { "disableBodyPruning": true @@ -444,7 +444,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"compactAbbr\": \"\",\n \"compactAdverseActionsNotificationEmails\": [\n \"\",\n \"\"\n ],\n \"compactName\": \"\",\n \"compactOperationsTeamEmails\": [\n \"\",\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"wa\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"va\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}", + "body": "{\n \"compactAbbr\": \"\",\n \"compactAdverseActionsNotificationEmails\": [\n \"\",\n \"\"\n ],\n \"compactName\": \"\",\n \"compactOperationsTeamEmails\": [\n \"\",\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"md\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"az\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -453,7 +453,7 @@ "value": "application/json" } ], - "id": "5e922d0d-16a1-427f-84a1-c5a9a363df39", + "id": "24ccd08b-0d68-47ac-ac71-fe939c799892", "name": "200 response", "originalRequest": { "body": {}, @@ -491,7 +491,7 @@ }, { "event": [], - "id": "ea60e924-1a4d-4a82-ab18-124f32d22f6d", + "id": "20d241ec-1e4f-4b22-8205-f7ce2f7a934d", "name": "/v1/compacts/:compact", "protocolProfileBehavior": { "disableBodyPruning": true @@ -505,7 +505,7 @@ "language": "json" } }, - "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"wa\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"ks\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" + "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"tn\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"wa\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" }, "description": {}, "header": [ @@ -556,7 +556,7 @@ "value": "application/json" } ], - "id": "ab0606b6-be4a-48ef-b795-acfa0672270e", + "id": "68da7087-1424-448e-816f-7afa67312189", "name": "200 response", "originalRequest": { "body": { @@ -567,7 +567,7 @@ "language": "json" } }, - "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"wa\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"ks\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" + "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"tn\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"wa\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" }, "header": [ { @@ -610,7 +610,7 @@ "item": [ { "event": [], - "id": "f76398a7-73fc-4e37-a4fe-a29529d29867", + "id": "1523ff84-c127-4744-b586-0b4047bc4a98", "name": "/v1/compacts/:compact/jurisdictions", "protocolProfileBehavior": { "disableBodyPruning": true @@ -663,7 +663,7 @@ "value": "application/json" } ], - "id": "4653aac0-f631-412b-9bf6-d4f43699bf5e", + "id": "e9d85cac-3310-417d-8c04-c89192494fad", "name": "200 response", "originalRequest": { "body": {}, @@ -705,7 +705,7 @@ "item": [ { "event": [], - "id": "2eb438e1-dfb0-44bd-adbd-6811d09bbc2c", + "id": "f872c07d-3525-4040-8fe9-35bda9071a72", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction", "protocolProfileBehavior": { "disableBodyPruning": true @@ -769,7 +769,7 @@ "value": "application/json" } ], - "id": "ab057823-5bc7-49f4-9ee4-09add2419179", + "id": "6c6aca1b-5196-4b57-8d5d-f9ca66c67349", "name": "200 response", "originalRequest": { "body": {}, @@ -809,7 +809,7 @@ }, { "event": [], - "id": "ebbbcb4d-8b09-4746-95ca-25e16afd1a0d", + "id": "b3b170d7-582a-4a2c-9a9a-f977ba6a9ad2", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction", "protocolProfileBehavior": { "disableBodyPruning": true @@ -886,7 +886,7 @@ "value": "application/json" } ], - "id": "1a3508c8-45c5-4267-b022-3031f5ee2695", + "id": "f7da98ba-bd29-4566-b5d1-5f7af899760e", "name": "200 response", "originalRequest": { "body": { @@ -970,7 +970,7 @@ } } ], - "id": "8f7e2286-26de-4b1f-ae10-2d52bcb2929b", + "id": "ba5dcf48-cc96-4eb5-b291-187deb64d4ae", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction/licenses/bulk-upload", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1027,7 +1027,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"upload\": {\n \"fields\": {\n \"incididunt_555\": \"\"\n },\n \"url\": \"\"\n }\n}", + "body": "{\n \"upload\": {\n \"fields\": {\n \"do__1\": \"\",\n \"esse_8\": \"\",\n \"velit_9\": \"\",\n \"et_eca\": \"\"\n },\n \"url\": \"\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -1036,7 +1036,7 @@ "value": "application/json" } ], - "id": "49a87d26-0946-4aae-9ee6-cff37b11aeea", + "id": "9bff1128-49a5-4129-b6c9-7cd9c6b8b3de", "name": "200 response", "originalRequest": { "body": {}, @@ -1096,7 +1096,7 @@ "item": [ { "event": [], - "id": "6df89efd-a66d-4a98-8e12-3f27ab199e8f", + "id": "0b401553-44a7-4558-ba67-ad86670b8cbb", "name": "/v1/compacts/:compact/providers/query", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1110,7 +1110,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"5d9241fc-627f-447a-a0e6-2b2277baf117\",\n \"jurisdiction\": \"ks\",\n \"givenName\": \"\",\n \"familyName\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"68691356-2c8a-40d3-89cf-b89183e229c8\",\n \"jurisdiction\": \"ky\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}" }, "description": {}, "header": [ @@ -1154,7 +1154,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"birthMonthDay\": \"08-32\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1954-07-29\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"al\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"41d828db-f6e9-4dbd-b9af-f483e0d06f49\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"1759-04-09\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"2396\",\n \"middleName\": \"\"\n },\n {\n \"birthMonthDay\": \"15-02\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"2943-08-29\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"ebe8ae48-c84f-4394-b925-19afb1c469a9\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"1672-07-16\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"1920\",\n \"middleName\": \"\"\n }\n ],\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"ascending\"\n }\n}", + "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"birthMonthDay\": \"01-07\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1558-01-23\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"tn\",\n \"licenseStatus\": \"active\",\n \"providerId\": \"58b1e082-9f3d-4557-be50-ddde20a55a74\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"2205-02-31\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"0623\",\n \"middleName\": \"\"\n },\n {\n \"birthMonthDay\": \"19-10\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"2243-10-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"md\",\n \"licenseStatus\": \"active\",\n \"providerId\": \"0b358cfc-74be-4c11-8101-cc062ad9fbae\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"1951-06-30\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"2029\",\n \"middleName\": \"\"\n }\n ],\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -1163,7 +1163,7 @@ "value": "application/json" } ], - "id": "030e47b5-b981-4002-bbee-676f0c02a000", + "id": "93c9577c-2511-4a7c-b4d1-e8222dd30057", "name": "200 response", "originalRequest": { "body": { @@ -1174,7 +1174,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"5d9241fc-627f-447a-a0e6-2b2277baf117\",\n \"jurisdiction\": \"ks\",\n \"givenName\": \"\",\n \"familyName\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"68691356-2c8a-40d3-89cf-b89183e229c8\",\n \"jurisdiction\": \"ky\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}" }, "header": [ { @@ -1222,7 +1222,7 @@ "item": [ { "event": [], - "id": "845c2956-9cf3-4c68-8386-21dc7a0fa91a", + "id": "cad0ba47-b4e3-45b2-81cc-07e3c1d69d46", "name": "/v1/compacts/:compact/providers/:providerId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1277,7 +1277,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"birthMonthDay\": \"19-29\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2223-12-05\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"oh\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1755-09-29\",\n \"dateOfIssuance\": \"1994-08-06\",\n \"dateOfRenewal\": \"2614-11-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ks\",\n \"previous\": {\n \"dateOfExpiration\": \"1382-03-30\",\n \"dateOfIssuance\": \"1010-09-24\",\n \"dateOfRenewal\": \"2238-03-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2286-12-07\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+169705366\",\n \"licenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"issuance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1246-10-27\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2896-04-01\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2825-08-31\",\n \"phoneNumber\": \"+0246304877\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2569-10-31\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"az\",\n \"previous\": {\n \"dateOfExpiration\": \"1215-12-16\",\n \"dateOfIssuance\": \"1129-12-06\",\n \"dateOfRenewal\": \"2158-05-07\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1724-12-26\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+23539194\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"lifting_encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1165-01-03\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"1967-08-30\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"1894-07-04\",\n \"phoneNumber\": \"+04189833\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1162-12-26\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"md\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"middleName\": \"\",\n \"providerId\": \"981397ce-fa77-4ed4-a44e-25ecf102a958\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"a652f834-acc8-4681-b909-46ee53494605\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"888382e9-1794-4c21-9366-4ed523901966\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"2917-02-12\",\n \"ssnLastFour\": \"6928\",\n \"phoneNumber\": \"+76732543\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2521-11-05\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1857-09-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3aeb03b9-b96d-4bb2-9b4f-341e50123933\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2748-12-12\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1843-04-03\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2572-03-24\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"f00229d0-b3f5-4bd9-b0e3-9415eb52268b\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1000-09-06\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1331-11-14\",\n \"dateOfIssuance\": \"1588-05-30\",\n \"dateOfRenewal\": \"2693-12-31\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"oh\",\n \"previous\": {\n \"dateOfExpiration\": \"1500-01-06\",\n \"dateOfIssuance\": \"1718-12-04\",\n \"dateOfRenewal\": \"1258-08-31\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2107-04-05\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+41499628297\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"other\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1125-04-13\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"1602-03-13\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2305-12-31\",\n \"phoneNumber\": \"+68419329788\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1870-05-30\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ks\",\n \"previous\": {\n \"dateOfExpiration\": \"2303-11-31\",\n \"dateOfIssuance\": \"2827-12-06\",\n \"dateOfRenewal\": \"1874-06-05\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1981-11-18\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+35309281959\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2151-10-15\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"1608-05-10\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"1757-10-08\",\n \"phoneNumber\": \"+88645057\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2728-03-30\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"middleName\": \"\",\n \"providerId\": \"331b9a04-3819-46a9-82db-133316566a37\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"dfa9b698-6ee0-4e2f-94ee-24d83987666c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"5e835f9a-6b62-4aaa-bc86-27db21f905ce\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"2542-05-16\",\n \"ssnLastFour\": \"7522\",\n \"phoneNumber\": \"+671890341856\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1552-10-08\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1645-05-28\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"528beca2-d37c-486c-a7c0-623dbb8d64ea\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2491-08-26\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2870-12-09\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2897-12-24\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d17fc19c-fa5a-4776-825c-0f851e2c4c75\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1257-12-06\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2059-12-06\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"co\",\n \"previous\": {\n \"administratorSetStatus\": \"inactive\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1097-10-31\",\n \"licenseJurisdiction\": \"va\",\n \"compact\": \"cosm\",\n \"providerId\": \"440453a8-af65-476e-9d27-533483bb8b42\",\n \"jurisdiction\": \"tn\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1932-12-04\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"e10462ee-8c85-4250-8713-92ccf431de2f\",\n \"jurisdiction\": \"md\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"tn\",\n \"previous\": {\n \"administratorSetStatus\": \"inactive\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1369-01-01\",\n \"licenseJurisdiction\": \"tn\",\n \"compact\": \"cosm\",\n \"providerId\": \"719411e6-26f3-4377-bd04-ebb1ba9fcbbb\",\n \"jurisdiction\": \"va\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"other\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1029-11-03\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"723b1674-81f6-437a-9430-81602d9a635c\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n }\n ],\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"va\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"47eb043c-9bab-4a88-97d9-3f6fbf4c18d8\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"4ccce5bc-4c50-48f1-a3c4-519f098404ba\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"176f294a-53ed-41d5-a4f5-944b520fd4cc\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1529-11-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1617-07-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"aeaff713-4948-4c75-86f6-ef2e09963604\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2639-10-31\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2681-12-24\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2473-02-20\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3f9d0c76-8dcd-415e-8152-e9883564a022\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2430-05-01\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1017-03-05\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ks\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1521-02-30\",\n \"licenseJurisdiction\": \"al\",\n \"compact\": \"cosm\",\n \"providerId\": \"190255de-3b03-4ee7-949d-90e9aa545b81\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"lifting_encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1951-11-01\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"cb017e6a-c29d-44c3-a59c-70dc29975fad\",\n \"jurisdiction\": \"va\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"active\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ks\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1472-04-04\",\n \"licenseJurisdiction\": \"wa\",\n \"compact\": \"cosm\",\n \"providerId\": \"d8372770-6d4f-48d0-9898-a62595d22a0c\",\n \"jurisdiction\": \"co\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"expiration\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1713-04-30\",\n \"licenseJurisdiction\": \"ks\",\n \"compact\": \"cosm\",\n \"providerId\": \"6fae54e3-ed49-4093-8275-7ed80ea7fe95\",\n \"jurisdiction\": \"tn\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n }\n ],\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"co\",\n \"licenseType\": \"esthetician\",\n \"providerId\": \"a3be6506-c659-446a-b2e6-d8e184f8a0c2\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"92b8e7e1-2b6b-411c-a98a-7a92c3e1d064\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"c20e1708-5ffd-4c63-83c0-fff6bd34245b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1729-12-09\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1342-02-06\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"174fa4b3-09bb-4c18-8122-d92233fcb464\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1630-10-27\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1259-03-09\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1302-04-26\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"33b802e6-4afb-446c-a156-1a73f155dc18\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2788-10-06\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"providerId\": \"9bbed952-418f-46dd-a4fe-9e94dc9b4fe7\",\n \"type\": \"provider\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1327-08-30\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"8099\",\n \"licenseStatus\": \"active\",\n \"middleName\": \"\"\n}", + "body": "{\n \"birthMonthDay\": \"13-12\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1162-10-27\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"md\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1748-10-28\",\n \"dateOfIssuance\": \"1380-10-03\",\n \"dateOfRenewal\": \"2755-06-03\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ky\",\n \"previous\": {\n \"dateOfExpiration\": \"1442-06-29\",\n \"dateOfIssuance\": \"2289-08-03\",\n \"dateOfRenewal\": \"1603-11-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1769-11-01\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+294715100\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"expiration\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1945-07-02\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"1692-03-31\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2188-12-25\",\n \"phoneNumber\": \"+28690665880218\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2145-10-04\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"tn\",\n \"previous\": {\n \"dateOfExpiration\": \"2770-12-07\",\n \"dateOfIssuance\": \"2760-12-20\",\n \"dateOfRenewal\": \"1409-10-31\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1046-10-02\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+95908841\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2859-11-29\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2122-12-22\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"1891-01-30\",\n \"phoneNumber\": \"+104354584\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1067-03-30\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"oh\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"esthetician\",\n \"middleName\": \"\",\n \"providerId\": \"02e485d4-8e85-422b-9902-ee5a076e501e\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"0611e976-8b22-49ec-9115-91d968c5678e\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"ac923355-31dd-41cd-908e-3380f7f3a972\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"1339-10-18\",\n \"ssnLastFour\": \"4772\",\n \"phoneNumber\": \"+607349906984\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1883-09-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2813-11-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"f69c9b2e-b369-4315-9ba2-4cad07ff7d3e\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2003-12-07\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1886-12-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1069-09-05\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"25c09f89-ff99-4a55-af99-365c48b3e2eb\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1868-12-10\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"2260-11-29\",\n \"dateOfIssuance\": \"1414-04-24\",\n \"dateOfRenewal\": \"2113-03-31\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"co\",\n \"previous\": {\n \"dateOfExpiration\": \"1242-02-07\",\n \"dateOfIssuance\": \"2095-09-05\",\n \"dateOfRenewal\": \"2632-11-17\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2650-08-30\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+82247346\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"expiration\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1479-11-03\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"1439-11-31\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2290-03-29\",\n \"phoneNumber\": \"+23569520415\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1438-10-08\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"wa\",\n \"previous\": {\n \"dateOfExpiration\": \"1534-01-08\",\n \"dateOfIssuance\": \"2366-01-30\",\n \"dateOfRenewal\": \"2098-08-12\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1911-12-11\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+6692858316\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1138-07-19\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2351-10-30\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2579-10-09\",\n \"phoneNumber\": \"+537683839466\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1865-04-30\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"middleName\": \"\",\n \"providerId\": \"819785c9-cc4d-4498-91ed-1a7514e9df25\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"8b3b19e8-d724-4525-b0cb-4692b51a3e8f\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"5ace5361-1234-49c5-9ab3-7bbaf2890e98\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"2587-10-17\",\n \"ssnLastFour\": \"7501\",\n \"phoneNumber\": \"+25692983898462\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1121-10-21\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2857-08-08\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"4b29d962-5102-4386-815b-db49fc3ff45b\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2187-11-09\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2084-04-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2596-06-02\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"4da0a9c0-3ed3-47a2-a03f-80ca1485be75\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2280-04-30\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1650-10-30\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"va\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1271-09-01\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"d6c3cffb-eb6d-446c-954c-f20d01fd6308\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"other\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"2267-03-30\",\n \"licenseJurisdiction\": \"ks\",\n \"compact\": \"cosm\",\n \"providerId\": \"1f813139-6046-44d9-b137-ec15888bc882\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"al\",\n \"previous\": {\n \"administratorSetStatus\": \"inactive\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2043-11-31\",\n \"licenseJurisdiction\": \"al\",\n \"compact\": \"cosm\",\n \"providerId\": \"e9a5e1a9-b775-4b65-ac4c-78c37b502bb0\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1780-12-19\",\n \"licenseJurisdiction\": \"tn\",\n \"compact\": \"cosm\",\n \"providerId\": \"5b65a238-3800-4893-b5de-14fb0219992e\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n }\n ],\n \"jurisdiction\": \"tn\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"2f12808e-ddf1-40ba-a927-f701ae395a30\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"3e2a9fd4-e600-44e7-a57e-4a65109a25de\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"1dfc678a-da48-44b9-a410-2adab3ed2da8\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1320-03-07\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1531-11-12\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"a342b6b8-a85d-42ff-a845-2cae57b19ef7\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2159-07-03\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2279-01-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1833-11-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"9f14499f-b9f0-4bea-a8ad-310d9c847248\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1411-03-09\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1080-06-26\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"va\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2302-01-31\",\n \"licenseJurisdiction\": \"ky\",\n \"compact\": \"cosm\",\n \"providerId\": \"0e96f8da-f33f-4ce7-8b4e-c7737aed8660\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"other\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1565-10-05\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"7562d31b-deab-4463-8f0e-96c7eab3fe2a\",\n \"jurisdiction\": \"md\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"al\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2652-05-21\",\n \"licenseJurisdiction\": \"oh\",\n \"compact\": \"cosm\",\n \"providerId\": \"8f5fb044-5f33-460c-8eb2-1a499708c7f1\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"2274-12-18\",\n \"licenseJurisdiction\": \"ky\",\n \"compact\": \"cosm\",\n \"providerId\": \"bbd27cd0-eade-482c-a1fa-87dd77c91fc7\",\n \"jurisdiction\": \"tn\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"active\"\n }\n }\n ],\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"ks\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"a0deec5c-78a1-4b88-a440-26b76520eb84\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"0d7ce51f-ca97-4bb2-8d04-958c717eba10\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"fafea83d-fdfa-4828-8d80-57d1d284310b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1191-11-07\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2496-09-29\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"41ea242f-ac9e-4be6-bb84-e011fca959c4\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1895-06-20\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2572-11-28\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2193-11-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3f184c16-4820-4c49-82cc-530c8c25a643\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2674-08-30\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"providerId\": \"ae5c146b-b96d-424c-b30a-3cd876ffab7d\",\n \"type\": \"provider\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2811-09-27\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"1415\",\n \"licenseStatus\": \"inactive\",\n \"middleName\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -1286,7 +1286,7 @@ "value": "application/json" } ], - "id": "2cd97d97-bf93-4ab2-9714-f7f4d48321aa", + "id": "6a35f77d-733b-4e59-9be9-2e666234773c", "name": "200 response", "originalRequest": { "body": {}, @@ -1344,7 +1344,7 @@ "item": [ { "event": [], - "id": "22c75de1-18b6-4d92-8a3a-a5d735547c95", + "id": "25de4fb2-348b-4328-882b-d1cc8cf13609", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1358,7 +1358,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2247-08-30\",\n \"encumbranceType\": \"completion of continuing education\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2353-07-30\",\n \"encumbranceType\": \"fine\"\n}" }, "description": {}, "header": [ @@ -1447,7 +1447,7 @@ "value": "application/json" } ], - "id": "762c99c8-ed9f-456a-9697-6b3cf4faf322", + "id": "49e7abd9-1aab-4f1d-8ab6-1a92131696ab", "name": "200 response", "originalRequest": { "body": { @@ -1458,7 +1458,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2247-08-30\",\n \"encumbranceType\": \"completion of continuing education\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2353-07-30\",\n \"encumbranceType\": \"fine\"\n}" }, "header": [ { @@ -1509,7 +1509,7 @@ "item": [ { "event": [], - "id": "abf93958-3268-4ee6-9295-657334e05417", + "id": "a7f8957e-c509-47b1-b28f-6db1c7a5f630", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance/:encumbranceId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1523,7 +1523,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1546-10-02\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"1810-11-01\"\n}" }, "description": {}, "header": [ @@ -1623,7 +1623,7 @@ "value": "application/json" } ], - "id": "c547abc3-cc70-4bf4-9450-f0b5996f0c83", + "id": "30870140-107d-41f0-9c05-92d06f8223c1", "name": "200 response", "originalRequest": { "body": { @@ -1634,7 +1634,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1546-10-02\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"1810-11-01\"\n}" }, "header": [ { @@ -1692,7 +1692,7 @@ "item": [ { "event": [], - "id": "ed5fb33b-2e19-494e-ad7d-3b0fd49c12d2", + "id": "34ff2083-eddb-4583-9754-0ce5675bab10", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1795,7 +1795,7 @@ "value": "application/json" } ], - "id": "8936d0cb-4c49-41c4-925e-d5ab16ec5c9c", + "id": "80be1ff4-b49d-49f2-aa24-9ec881a91355", "name": "200 response", "originalRequest": { "body": { @@ -1857,7 +1857,7 @@ "item": [ { "event": [], - "id": "d5998329-7445-46c6-a87f-85e5117f6575", + "id": "073c75ea-4f53-416f-9a34-cf53c84485c3", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation/:investigationId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1871,7 +1871,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2988-11-25\",\n \"encumbranceType\": \"fine\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"1241-05-01\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "description": {}, "header": [ @@ -1971,7 +1971,7 @@ "value": "application/json" } ], - "id": "16ff65fd-6639-4896-8632-1cbef343e292", + "id": "01b9554d-be9a-4b2b-b666-1e699ac2d303", "name": "200 response", "originalRequest": { "body": { @@ -1982,7 +1982,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2988-11-25\",\n \"encumbranceType\": \"fine\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"1241-05-01\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "header": [ { @@ -2070,7 +2070,7 @@ "item": [ { "event": [], - "id": "7ef5fbfd-2a81-4ca7-a999-01fdebd821c4", + "id": "50fd8bce-65ee-4814-bcfe-3aec6f945394", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2084,7 +2084,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2247-08-30\",\n \"encumbranceType\": \"completion of continuing education\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2353-07-30\",\n \"encumbranceType\": \"fine\"\n}" }, "description": {}, "header": [ @@ -2173,7 +2173,7 @@ "value": "application/json" } ], - "id": "83e464b4-5367-4aef-ad7e-90197622d469", + "id": "3251d2e5-7206-4204-9057-22431e6a59dc", "name": "200 response", "originalRequest": { "body": { @@ -2184,7 +2184,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2247-08-30\",\n \"encumbranceType\": \"completion of continuing education\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2353-07-30\",\n \"encumbranceType\": \"fine\"\n}" }, "header": [ { @@ -2235,7 +2235,7 @@ "item": [ { "event": [], - "id": "39b08c0d-662d-4ed4-afb0-6ba9001f0ce8", + "id": "381fe7c7-3cd0-4e12-812b-4a8934c935f8", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance/:encumbranceId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2249,7 +2249,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1546-10-02\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"1810-11-01\"\n}" }, "description": {}, "header": [ @@ -2349,7 +2349,7 @@ "value": "application/json" } ], - "id": "9b478e5a-0991-42ef-80a4-c98c649ab4dd", + "id": "32b982c2-3026-4d2f-a56d-5f06fc7ce730", "name": "200 response", "originalRequest": { "body": { @@ -2360,7 +2360,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1546-10-02\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"1810-11-01\"\n}" }, "header": [ { @@ -2418,7 +2418,7 @@ "item": [ { "event": [], - "id": "242ac733-7e86-4530-90e2-55919686e8d3", + "id": "857069d8-ff0e-4483-a186-8ad18d82a970", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2521,7 +2521,7 @@ "value": "application/json" } ], - "id": "755a1f8b-a044-42c0-8874-3f7086f0a81f", + "id": "308bcd04-72e9-4875-9aff-bd6083c931be", "name": "200 response", "originalRequest": { "body": { @@ -2583,7 +2583,7 @@ "item": [ { "event": [], - "id": "916f9056-091c-4127-972c-d58097d2154b", + "id": "ccbf0022-bdc8-48fb-b0fe-d03d920813e1", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation/:investigationId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2597,7 +2597,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2988-11-25\",\n \"encumbranceType\": \"fine\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"1241-05-01\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "description": {}, "header": [ @@ -2697,7 +2697,7 @@ "value": "application/json" } ], - "id": "dfd67bd7-ea8f-4ec1-bffd-bcb7a9a190e0", + "id": "6e7f4f73-58fc-4799-9f2a-7de638b127b8", "name": "200 response", "originalRequest": { "body": { @@ -2708,7 +2708,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"2988-11-25\",\n \"encumbranceType\": \"fine\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"encumbranceEffectiveDate\": \"1241-05-01\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "header": [ { @@ -2781,7 +2781,7 @@ "item": [ { "event": [], - "id": "bb648299-5be8-47b7-be14-16c1ff4982a5", + "id": "9a677864-f818-4d0e-a1b1-25d6f09f2b89", "name": "/v1/compacts/:compact/providers/:providerId/ssn", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2837,7 +2837,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"ssn\": \"688-70-3643\"\n}", + "body": "{\n \"ssn\": \"100-84-1716\"\n}", "code": 200, "cookie": [], "header": [ @@ -2846,7 +2846,7 @@ "value": "application/json" } ], - "id": "73658cf2-d30a-4e68-8c4c-3607af6c954a", + "id": "8ba643e7-950a-4619-9486-ca5d69b892cc", "name": "200 response", "originalRequest": { "body": {}, @@ -2899,7 +2899,7 @@ "item": [ { "event": [], - "id": "88b549c5-5289-4490-8473-ed0418c4202b", + "id": "be703c23-2976-4eff-9fa4-ef3f4563e622", "name": "/v1/compacts/:compact/staff-users", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2943,7 +2943,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"users\": [\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"incididunt2a7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"veniam_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"consequat_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"ullamco_3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"mollit_b\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"aute_f5b\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"inactive\",\n \"userId\": \"\"\n },\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"laboris_3b\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"incididunt_20\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n }\n ]\n}", + "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"users\": [\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"Lorem7f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"Excepteur7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"enim_e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"Excepteurc28\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"tempor__\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"qui7db\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"eu7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"in_e77\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"Lorem8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"proident_9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"magnaaf\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"inactive\",\n \"userId\": \"\"\n },\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"dolor227\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"occaecat5a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"Lorem_6\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"commodo_0e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n }\n ]\n}", "code": 200, "cookie": [], "header": [ @@ -2961,7 +2961,7 @@ "value": "" } ], - "id": "89eb9b76-972f-4536-9329-f7eb777f5bfd", + "id": "60d0df6e-2047-4ab8-859a-662961b7afd1", "name": "200 response", "originalRequest": { "body": {}, @@ -3000,7 +3000,7 @@ }, { "event": [], - "id": "1131a085-2a0d-4b72-b750-737f28f15003", + "id": "d07cc353-2ee9-4487-b8cf-6d434c94f68d", "name": "/v1/compacts/:compact/staff-users", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3014,7 +3014,7 @@ "language": "json" } }, - "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"qui8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"velit_9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"voluptate2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"pariatur8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"amet1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" }, "description": {}, "header": [ @@ -3057,7 +3057,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"ad_f6\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"id_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"occaecat_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"cillum_3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"sit_f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"dolore410\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"dolorefe\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"quis593\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"nostrud8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"proident_c0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -3075,7 +3075,7 @@ "value": "" } ], - "id": "0ee9d8bc-b043-4768-81f5-1a96c252f342", + "id": "31824c98-5c6b-4530-a2cc-32e0493b9feb", "name": "200 response", "originalRequest": { "body": { @@ -3086,7 +3086,7 @@ "language": "json" } }, - "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"qui8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"velit_9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"voluptate2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"pariatur8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"amet1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" }, "header": [ { @@ -3130,7 +3130,7 @@ "item": [ { "event": [], - "id": "3d324393-e3a4-4e5c-bef3-2afd6eea9442", + "id": "fd2751ef-b361-4fa6-95fd-0c2c8d4e68c3", "name": "/v1/compacts/:compact/staff-users/:userId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3185,7 +3185,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"ad_f6\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"id_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"occaecat_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"cillum_3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"sit_f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"dolore410\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"dolorefe\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"quis593\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"nostrud8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"proident_c0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -3203,7 +3203,7 @@ "value": "" } ], - "id": "9687a7a7-7b09-46eb-80d2-d2d1be30c66c", + "id": "dc3e2317-7e88-4639-b8b4-a8712ce0a51f", "name": "200 response", "originalRequest": { "body": {}, @@ -3250,7 +3250,7 @@ "value": "application/json" } ], - "id": "a91d277d-7104-4b26-9dc7-cd1a281de9fd", + "id": "0b75e10a-2134-4b45-8bee-e916c327a062", "name": "404 response", "originalRequest": { "body": {}, @@ -3290,7 +3290,7 @@ }, { "event": [], - "id": "5253d0a5-635a-44c4-a065-6f5b6688d12f", + "id": "de36272a-f097-49c5-85bd-b2b4d0942e12", "name": "/v1/compacts/:compact/staff-users/:userId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3354,7 +3354,7 @@ "value": "application/json" } ], - "id": "886dad9b-e40d-4ac7-9c10-94fa4afe8480", + "id": "512cae65-8486-4d18-8a9d-fdf562ed3912", "name": "200 response", "originalRequest": { "body": {}, @@ -3401,7 +3401,7 @@ "value": "application/json" } ], - "id": "3b1f81db-220a-4662-a742-9bd3ff395630", + "id": "aef5e7fb-73ff-4e9f-9a1f-f880c6074054", "name": "404 response", "originalRequest": { "body": {}, @@ -3441,7 +3441,7 @@ }, { "event": [], - "id": "fbecc5d7-02f2-4463-80ee-8dcc71801b7c", + "id": "89311527-1810-485f-adb9-4e08eac121c2", "name": "/v1/compacts/:compact/staff-users/:userId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3455,7 +3455,7 @@ "language": "json" } }, - "raw": "{\n \"permissions\": {\n \"adipisicing__d\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"Ut_2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"ullamco_769\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"permissions\": {\n \"sed__\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"et9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"deserunt649\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"eu31e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"labore307\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"Excepteur_fc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"anim_99a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"esse_47\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"minim12b\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" }, "description": {}, "header": [ @@ -3509,7 +3509,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"ad_f6\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"id_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"occaecat_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"cillum_3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"sit_f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"dolore410\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"dolorefe\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"quis593\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"nostrud8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"proident_c0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -3527,7 +3527,7 @@ "value": "" } ], - "id": "f8cb39c8-919e-4947-9660-07282adb058a", + "id": "5be7fd31-0f34-46a3-ada6-5b349c67680a", "name": "200 response", "originalRequest": { "body": { @@ -3538,7 +3538,7 @@ "language": "json" } }, - "raw": "{\n \"permissions\": {\n \"adipisicing__d\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"Ut_2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"ullamco_769\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"permissions\": {\n \"sed__\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"et9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"deserunt649\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"eu31e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"labore307\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"Excepteur_fc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"anim_99a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"esse_47\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"minim12b\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" }, "header": [ { @@ -3587,7 +3587,7 @@ "value": "application/json" } ], - "id": "9a1705af-9e3c-415f-a9cc-13ab0a69ae92", + "id": "2c814712-0e23-4e8d-90d7-abf5f5d1e5aa", "name": "404 response", "originalRequest": { "body": { @@ -3598,7 +3598,7 @@ "language": "json" } }, - "raw": "{\n \"permissions\": {\n \"adipisicing__d\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"Ut_2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"ullamco_769\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"permissions\": {\n \"sed__\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"et9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"deserunt649\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"eu31e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"labore307\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"Excepteur_fc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"anim_99a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"esse_47\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"minim12b\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n }\n}" }, "header": [ { @@ -3643,7 +3643,7 @@ "item": [ { "event": [], - "id": "609ece77-7a62-406c-a981-bc1b49746330", + "id": "941254d2-160d-4551-9c36-3eaa543d024c", "name": "/v1/compacts/:compact/staff-users/:userId/reinvite", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3708,7 +3708,7 @@ "value": "application/json" } ], - "id": "0ab0965e-da7e-424f-a497-020710104c35", + "id": "7b16e72f-5330-4a26-aa4c-72e80118f959", "name": "200 response", "originalRequest": { "body": {}, @@ -3756,7 +3756,7 @@ "value": "application/json" } ], - "id": "6c9ff999-21ac-4219-8564-28bf985844b5", + "id": "3c214ac2-938b-46df-b5d5-2f3cf082832d", "name": "404 response", "originalRequest": { "body": {}, @@ -3821,7 +3821,7 @@ "item": [ { "event": [], - "id": "a7aad06b-3573-44ff-b189-d3e48c49f082", + "id": "9c0b97d1-d0e6-4d2f-87cb-49926c6c81cb", "name": "/v1/flags/:flagId/check", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3838,7 +3838,7 @@ "language": "json" } }, - "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"occaecat_d4\": \"\"\n }\n }\n}" + "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"ipsum3f\": \"\",\n \"enim_4d\": \"\"\n }\n }\n}" }, "description": {}, "header": [ @@ -3890,7 +3890,7 @@ "value": "application/json" } ], - "id": "f53f0917-f9ed-4876-ae88-8333e28c3fee", + "id": "b2f5fd9c-1be3-44c6-ac44-3222b31c6e57", "name": "200 response", "originalRequest": { "body": { @@ -3901,7 +3901,7 @@ "language": "json" } }, - "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"occaecat_d4\": \"\"\n }\n }\n}" + "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"ipsum3f\": \"\",\n \"enim_4d\": \"\"\n }\n }\n}" }, "header": [ { @@ -3955,7 +3955,7 @@ "item": [ { "event": [], - "id": "cd64eaf9-4ae0-4494-958b-d0370c451143", + "id": "ae8dfc6d-4808-4578-9d4e-9f6f6a4fdd39", "name": "/v1/public/compacts/:compact/jurisdictions", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4012,7 +4012,7 @@ "value": "application/json" } ], - "id": "da6f6b2b-fbb3-4853-b2fc-909f66cd3037", + "id": "839b4f41-6d49-477d-8539-f12b97765d2c", "name": "200 response", "originalRequest": { "body": {}, @@ -4053,7 +4053,7 @@ "item": [ { "event": [], - "id": "26ec27f2-6db1-4d6c-8689-65c5a67f57cd", + "id": "e1fbb205-a354-496c-b77d-068f5d980eee", "name": "/v1/public/compacts/:compact/providers/query", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4070,7 +4070,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"5d9241fc-627f-447a-a0e6-2b2277baf117\",\n \"jurisdiction\": \"ks\",\n \"givenName\": \"\",\n \"familyName\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"68691356-2c8a-40d3-89cf-b89183e229c8\",\n \"jurisdiction\": \"ky\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}" }, "description": {}, "header": [ @@ -4115,7 +4115,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"tn\",\n \"providerId\": \"04174472-f8ac-43c0-9869-56c7a8edb6d0\",\n \"type\": \"provider\",\n \"middleName\": \"\",\n \"suffix\": \"\",\n \"dateOfUpdate\": \"\"\n },\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"wa\",\n \"providerId\": \"1731d6f8-c615-4181-83d8-019cbfa7ba56\",\n \"type\": \"provider\",\n \"middleName\": \"\",\n \"suffix\": \"\",\n \"dateOfUpdate\": \"\"\n }\n ],\n \"query\": {\n \"providerId\": \"d9b8b323-f0aa-4dd8-a9fd-c2ba358e4626\",\n \"jurisdiction\": \"al\",\n \"givenName\": \"\",\n \"familyName\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"ascending\"\n }\n}", + "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseNumber\": \"\",\n \"licenseType\": \"\",\n \"providerId\": \"90d7db58-884d-4988-9c77-b4339bdceb40\"\n },\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseNumber\": \"\",\n \"licenseType\": \"\",\n \"providerId\": \"7e956e96-d348-4e8c-9f11-5a5e79adaadb\"\n }\n ],\n \"query\": {\n \"providerId\": \"d7a58db9-7feb-46fa-86d1-3f72b522e27d\",\n \"jurisdiction\": \"al\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"ascending\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -4124,7 +4124,7 @@ "value": "application/json" } ], - "id": "132e3288-79c0-47ad-9c0e-6762cd5a43ff", + "id": "988d65c1-a607-4f7a-8aa3-82ae6ec05eb4", "name": "200 response", "originalRequest": { "body": { @@ -4135,7 +4135,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"5d9241fc-627f-447a-a0e6-2b2277baf117\",\n \"jurisdiction\": \"ks\",\n \"givenName\": \"\",\n \"familyName\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"68691356-2c8a-40d3-89cf-b89183e229c8\",\n \"jurisdiction\": \"ky\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}" }, "header": [ { @@ -4176,7 +4176,7 @@ "item": [ { "event": [], - "id": "6baae5cf-6803-4947-b500-84f807adf551", + "id": "7f5605d6-1f5c-4853-ad87-fade02f6fe93", "name": "/v1/public/compacts/:compact/providers/:providerId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4235,7 +4235,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"oh\",\n \"providerId\": \"cec770f5-c0df-4b78-a81b-e15e12217c8e\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2140-11-24\",\n \"jurisdiction\": \"va\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"648a71cc-a5e3-4032-ba26-25af2c996c6a\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"esthetician\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1832-04-24\",\n \"licenseJurisdiction\": \"tn\"\n },\n \"providerId\": \"ac95eae2-3dbe-43b1-a6a8-b39baceab06a\",\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"lifting_encumbrance\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1163-08-05\",\n \"licenseJurisdiction\": \"al\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"cosmetologist\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"2470-12-09\",\n \"licenseJurisdiction\": \"co\"\n },\n \"providerId\": \"96f7a30f-5d68-4d0f-a24e-302c08eca76a\",\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"2192-10-30\",\n \"licenseJurisdiction\": \"wa\"\n }\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1092-12-24\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1398-04-06\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3b767fe5-5c20-413b-b4d7-249f48a1ec11\",\n \"type\": \"adverseAction\",\n \"effectiveLiftDate\": \"2910-05-05\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1544-12-05\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2738-10-10\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"252c844d-ce9f-4eab-a61b-bb54cfc91b1a\",\n \"type\": \"adverseAction\",\n \"effectiveLiftDate\": \"2399-11-24\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2975-12-12\",\n \"jurisdiction\": \"al\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"9c64b3fa-e690-4533-8334-ca0afee60b91\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"esthetician\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1791-02-11\",\n \"licenseJurisdiction\": \"ky\"\n },\n \"providerId\": \"757aecba-8e55-40f6-a358-f12e9d063389\",\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"deactivation\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"2452-10-23\",\n \"licenseJurisdiction\": \"wa\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"cosmetologist\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1147-11-31\",\n \"licenseJurisdiction\": \"tn\"\n },\n \"providerId\": \"653bfb61-d1f4-49d6-8c15-9059f0fe7204\",\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"lifting_encumbrance\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1642-12-25\",\n \"licenseJurisdiction\": \"va\"\n }\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1431-10-04\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2078-06-05\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"1211f046-0b89-4b07-b126-729d9c94c113\",\n \"type\": \"adverseAction\",\n \"effectiveLiftDate\": \"1467-07-10\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2931-12-13\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1686-11-05\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"9c2ca79d-1319-4ad9-ac4d-e5dcc2d3fd89\",\n \"type\": \"adverseAction\",\n \"effectiveLiftDate\": \"2427-12-17\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"suffix\": \"\"\n}", + "body": "{\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"wa\",\n \"providerId\": \"9d30e187-2ab4-433a-809b-4f8116c630cb\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1210-11-04\",\n \"jurisdiction\": \"wa\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"5afe7161-4b34-420b-9453-aff56cfa13cf\",\n \"status\": \"active\",\n \"type\": \"privilege\"\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1707-04-02\",\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"b0e66df9-20cb-4c3e-a789-df503e09c6e0\",\n \"status\": \"inactive\",\n \"type\": \"privilege\"\n }\n ],\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1971-09-31\",\n \"jurisdiction\": \"md\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"type\": \"license\"\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"2731-04-31\",\n \"jurisdiction\": \"md\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"type\": \"license\"\n }\n ],\n \"middleName\": \"\",\n \"suffix\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -4244,7 +4244,7 @@ "value": "application/json" } ], - "id": "477d562d-bc77-4d18-b988-57643163f581", + "id": "6088a552-8581-4f24-9c2a-779fcda23bcc", "name": "200 response", "originalRequest": { "body": {}, @@ -4295,7 +4295,7 @@ "item": [ { "event": [], - "id": "24e85428-bd0a-4a2f-975f-6097fc7547e0", + "id": "a84f5cd5-964c-41c5-8c8d-75ef9a0349fe", "name": "/v1/public/jurisdictions/live", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4341,7 +4341,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"in_c\": [\n \"wa\",\n \"az\"\n ]\n}", + "body": "{\n \"ut_3ec\": [\n \"ky\",\n \"va\"\n ],\n \"dolor3_f\": [\n \"tn\",\n \"az\"\n ]\n}", "code": 200, "cookie": [], "header": [ @@ -4350,7 +4350,7 @@ "value": "application/json" } ], - "id": "c77c8061-b02a-431d-aa06-201919a71e26", + "id": "cbc2b84f-8424-4f57-987e-7c3067b46d8d", "name": "200 response", "originalRequest": { "body": {}, @@ -4406,7 +4406,7 @@ "item": [ { "event": [], - "id": "5178ba8c-9b68-4319-b2f9-e931e8d57b64", + "id": "3f079b19-025c-4043-989e-566a4520b237", "name": "/v1/staff-users/me", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4438,7 +4438,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"ad_f6\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"id_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"occaecat_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"cillum_3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"sit_f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"dolore410\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"dolorefe\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"quis593\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"nostrud8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"proident_c0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -4456,7 +4456,7 @@ "value": "" } ], - "id": "4042f89e-f42d-4470-82cf-563e6385ed92", + "id": "e09174ec-4a47-4751-bbc2-212a4fa3dd89", "name": "200 response", "originalRequest": { "body": {}, @@ -4501,7 +4501,7 @@ "value": "application/json" } ], - "id": "977b0eae-332a-4d0c-ba12-ae72c0234cc3", + "id": "cd8847fc-2c5c-4eaf-9168-36dd2eb572ab", "name": "404 response", "originalRequest": { "body": {}, @@ -4539,7 +4539,7 @@ }, { "event": [], - "id": "0e771354-c3b8-4700-8ac0-14f10951bb29", + "id": "0275e2a9-389f-42fe-aabd-ef5d95a62957", "name": "/v1/staff-users/me", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4584,7 +4584,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"ad_f6\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"id_1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"occaecat_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"cillum_3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"sit_f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"dolore410\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n },\n \"dolorefe\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"readSSN\": \"\"\n },\n \"jurisdictions\": {\n \"quis593\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"nostrud8_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n },\n \"proident_c0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\",\n \"readSSN\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -4602,7 +4602,7 @@ "value": "" } ], - "id": "05388a56-3021-4d11-b3ae-598caae147ad", + "id": "64569e6a-a6a9-4fcf-bfc4-5cbd53624ab9", "name": "200 response", "originalRequest": { "body": { @@ -4660,7 +4660,7 @@ "value": "application/json" } ], - "id": "d3f9f3c8-5f32-48b6-97a4-248ee626df2c", + "id": "dcf68eae-d03b-453f-8da1-744dd3a6c558", "name": "404 response", "originalRequest": { "body": { diff --git a/backend/cosmetology-app/docs/postman/postman-collection.json b/backend/cosmetology-app/docs/postman/postman-collection.json index 7c321aac1..0ce52dede 100644 --- a/backend/cosmetology-app/docs/postman/postman-collection.json +++ b/backend/cosmetology-app/docs/postman/postman-collection.json @@ -10,7 +10,7 @@ "type": "bearer" }, "info": { - "_postman_id": "f7b9902e-dab4-4941-99b1-f2c42f2edfa6", + "_postman_id": "e444fd71-91b5-46e4-bcac-fe1bb2ddf12a", "description": { "content": "", "type": "text/plain" @@ -410,7 +410,7 @@ "item": [ { "event": [], - "id": "aaf8d266-5468-4a6b-ae58-0b2ca29fbdad", + "id": "ae4dd3d5-9625-4003-b70c-6e0b1e0896d4", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction/licenses", "protocolProfileBehavior": { "disableBodyPruning": true @@ -424,7 +424,7 @@ "language": "json" } }, - "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2016-01-11\",\n \"dateOfExpiration\": \"1905-06-30\",\n \"dateOfIssuance\": \"1142-04-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"595-78-6083\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+84513167922177\",\n \"dateOfRenewal\": \"2876-10-16\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2421-12-03\",\n \"dateOfExpiration\": \"1924-12-31\",\n \"dateOfIssuance\": \"1961-06-17\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"999-36-3764\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+6196608142\",\n \"dateOfRenewal\": \"2580-06-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" + "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2047-09-31\",\n \"dateOfExpiration\": \"2778-12-30\",\n \"dateOfIssuance\": \"1961-10-22\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"ssn\": \"776-14-8717\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+375005223091\",\n \"dateOfRenewal\": \"1874-11-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1822-04-31\",\n \"dateOfExpiration\": \"2511-11-31\",\n \"dateOfIssuance\": \"2096-09-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"551-66-3213\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2352984283\",\n \"dateOfRenewal\": \"2319-11-05\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" }, "description": {}, "header": [ @@ -488,7 +488,7 @@ "value": "application/json" } ], - "id": "d324d0d1-33de-4c34-bdc4-72a11803ce22", + "id": "3dc7d85f-73ff-4370-be60-47ab18257e0c", "name": "200 response", "originalRequest": { "body": { @@ -499,7 +499,7 @@ "language": "json" } }, - "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2016-01-11\",\n \"dateOfExpiration\": \"1905-06-30\",\n \"dateOfIssuance\": \"1142-04-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"595-78-6083\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+84513167922177\",\n \"dateOfRenewal\": \"2876-10-16\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2421-12-03\",\n \"dateOfExpiration\": \"1924-12-31\",\n \"dateOfIssuance\": \"1961-06-17\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"999-36-3764\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+6196608142\",\n \"dateOfRenewal\": \"2580-06-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" + "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2047-09-31\",\n \"dateOfExpiration\": \"2778-12-30\",\n \"dateOfIssuance\": \"1961-10-22\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"ssn\": \"776-14-8717\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+375005223091\",\n \"dateOfRenewal\": \"1874-11-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1822-04-31\",\n \"dateOfExpiration\": \"2511-11-31\",\n \"dateOfIssuance\": \"2096-09-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"551-66-3213\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2352984283\",\n \"dateOfRenewal\": \"2319-11-05\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" }, "header": [ { @@ -540,7 +540,7 @@ }, { "_postman_previewlanguage": "json", - "body": "{\n \"message\": \"\",\n \"errors\": {\n \"anim_5c9\": {\n \"incididunt6\": [\n \"\",\n \"\"\n ]\n }\n }\n}", + "body": "{\n \"message\": \"\",\n \"errors\": {\n \"ullamco9\": {\n \"laboris6fd\": [\n \"\",\n \"\"\n ]\n }\n }\n}", "code": 400, "cookie": [], "header": [ @@ -549,7 +549,7 @@ "value": "application/json" } ], - "id": "c9392cc6-2bcd-4d49-9c76-2ce436d97b94", + "id": "9209a379-9a94-4192-b60e-141d660e1b6a", "name": "400 response", "originalRequest": { "body": { @@ -560,7 +560,7 @@ "language": "json" } }, - "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2016-01-11\",\n \"dateOfExpiration\": \"1905-06-30\",\n \"dateOfIssuance\": \"1142-04-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"595-78-6083\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+84513167922177\",\n \"dateOfRenewal\": \"2876-10-16\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2421-12-03\",\n \"dateOfExpiration\": \"1924-12-31\",\n \"dateOfIssuance\": \"1961-06-17\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"999-36-3764\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+6196608142\",\n \"dateOfRenewal\": \"2580-06-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" + "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2047-09-31\",\n \"dateOfExpiration\": \"2778-12-30\",\n \"dateOfIssuance\": \"1961-10-22\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"ssn\": \"776-14-8717\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+375005223091\",\n \"dateOfRenewal\": \"1874-11-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1822-04-31\",\n \"dateOfExpiration\": \"2511-11-31\",\n \"dateOfIssuance\": \"2096-09-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"551-66-3213\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2352984283\",\n \"dateOfRenewal\": \"2319-11-05\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" }, "header": [ { @@ -631,7 +631,7 @@ } } ], - "id": "7febd1cc-ed06-4812-9526-9b3dadc334a2", + "id": "94302ab8-108f-40dd-a5bb-01d1e6042939", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction/licenses/bulk-upload", "protocolProfileBehavior": { "disableBodyPruning": true @@ -688,7 +688,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"upload\": {\n \"fields\": {\n \"quis0e3\": \"\",\n \"consequat_fcf\": \"\",\n \"minime0\": \"\",\n \"minim_3\": \"\",\n \"occaecat988\": \"\"\n },\n \"url\": \"\"\n }\n}", + "body": "{\n \"upload\": {\n \"fields\": {\n \"ut_9c\": \"\",\n \"non_8f\": \"\"\n },\n \"url\": \"\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -697,7 +697,7 @@ "value": "application/json" } ], - "id": "8c059a2d-8736-41b6-9fea-9144a01e3aef", + "id": "d149ce75-f3ec-4640-a52e-95c04db4d14e", "name": "200 response", "originalRequest": { "body": {}, diff --git a/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json b/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json index 600edc38b..14e44fe22 100644 --- a/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json +++ b/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "SearchApi", - "version": "2026-02-25T22:40:54Z" + "version": "2026-03-13T19:50:46Z" }, "servers": [ { @@ -34,7 +34,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboSearcFlaGc2hNzmIy" + "$ref": "#/components/schemas/SandboSearc6bIbGbp1agwX" } } }, @@ -46,7 +46,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboSearcEzLOjtUlVHxz" + "$ref": "#/components/schemas/SandboSearce1qe0F7F8UqP" } } } @@ -64,42 +64,7 @@ }, "components": { "schemas": { - "SandboSearcFlaGc2hNzmIy": { - "required": [ - "query" - ], - "type": "object", - "properties": { - "search_after": { - "type": "array", - "description": "Sort values from the last hit of the previous page for cursor-based pagination" - }, - "size": { - "maximum": 100, - "minimum": 1, - "type": "integer", - "description": "Number of results to return" - }, - "query": { - "type": "object", - "description": "The OpenSearch query body" - }, - "from": { - "minimum": 0, - "type": "integer", - "description": "Starting document offset for pagination" - }, - "sort": { - "type": "array", - "description": "Sort order for results (required for search_after pagination)", - "items": { - "type": "object" - } - } - }, - "additionalProperties": false - }, - "SandboSearcEzLOjtUlVHxz": { + "SandboSearce1qe0F7F8UqP": { "required": [ "providers", "total" @@ -868,6 +833,41 @@ } } } + }, + "SandboSearc6bIbGbp1agwX": { + "required": [ + "query" + ], + "type": "object", + "properties": { + "search_after": { + "type": "array", + "description": "Sort values from the last hit of the previous page for cursor-based pagination" + }, + "size": { + "maximum": 100, + "minimum": 1, + "type": "integer", + "description": "Number of results to return" + }, + "query": { + "type": "object", + "description": "The OpenSearch query body" + }, + "from": { + "minimum": 0, + "type": "integer", + "description": "Starting document offset for pagination" + }, + "sort": { + "type": "array", + "description": "Sort order for results (required for search_after pagination)", + "items": { + "type": "object" + } + } + }, + "additionalProperties": false } }, "securitySchemes": { diff --git a/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json b/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json index 2b6e66209..39b9dd8b9 100644 --- a/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json +++ b/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json @@ -10,7 +10,7 @@ "type": "bearer" }, "info": { - "_postman_id": "f30acefe-591b-4aec-9f12-4617ae283540", + "_postman_id": "1369ff3a-aabc-4f1d-bfde-c195fb7e91e7", "description": { "content": "", "type": "text/plain" @@ -407,7 +407,7 @@ "item": [ { "event": [], - "id": "a4788cd8-d46e-4b3c-8a1c-3b794871904b", + "id": "02ee167c-b449-48bc-ba9b-05599c65e9f6", "name": "/v1/compacts/:compact/providers/search", "protocolProfileBehavior": { "disableBodyPruning": true @@ -465,7 +465,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"providers\": [\n {\n \"birthMonthDay\": \"05-29\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"va\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"3b2ce4ac-690b-4b4a-ad49-d103ddb258d7\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2545-10-31\",\n \"jurisdiction\": \"ky\",\n \"licenseJurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"66b2cb4c-5a1b-4017-a6c0-10f5133d592d\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"3a730722-0fbb-4416-a76c-188478993f9c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"0c54bcd0-11ab-44a8-ac50-a43fc5e6ef28\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1300-06-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2855-10-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"cb27b306-5c6f-41e5-b097-0174b801ba7f\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2657-02-09\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2351-06-16\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2222-11-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"2720cb02-0305-44cf-b43a-451635c74a89\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2260-12-08\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2673-11-09\",\n \"jurisdiction\": \"wa\",\n \"licenseJurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"73560e5e-920b-4705-a9b8-4cf0930ea1c1\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"b781e6ba-6ecf-446d-8630-d54f33141e27\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"ba1bd0aa-1b49-4d27-ba7c-82392c87e1b8\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2379-11-05\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1053-07-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"b051a452-b96c-4796-90ef-c3f4941b7673\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1250-11-06\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2007-11-08\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2103-12-17\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d75dc6ab-fe82-4455-8353-08e7125e7835\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2896-12-16\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"co\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1513-12-29\",\n \"dateOfIssuance\": \"2173-11-24\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"oh\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"5ba4090f-a7aa-47b2-b116-28e56b114adb\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"bc1e47fb-8544-4994-baa9-c6adb080921d\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"c499aa70-edb0-4eb4-a91b-42614e7881c7\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2954-12-08\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+54407065459586\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1653-12-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1139-03-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"95e1a5c7-94e8-466a-9f2f-d6f1168720d2\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2470-04-13\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2964-12-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1641-08-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5f79fbf8-c109-40e4-8c8d-c0f18aa5eaf2\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1357-12-01\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1127-09-29\",\n \"dateOfIssuance\": \"1057-09-17\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"al\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"\",\n \"providerId\": \"a10754e5-3999-446f-af51-feaa165b210e\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"5a02ef9c-de56-4fae-b93f-dd11c4127765\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"401a38f4-de8c-4ed1-b3b0-d5497bac644a\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1399-10-30\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+870840127811956\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1474-04-08\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2119-07-08\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"a9dfba6c-d9a2-4502-99d8-1a82d30ce204\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2497-04-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1118-07-23\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1523-06-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"1c02e6f1-da65-4d0c-bba9-7a56d0d29f7b\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1078-08-31\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n },\n {\n \"birthMonthDay\": \"12-32\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"co\",\n \"licenseStatus\": \"active\",\n \"providerId\": \"e039f355-1155-4647-bb13-e7e3b03ae353\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1882-08-31\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"413b00f0-92fb-4623-be0f-36648a089a4e\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"7c4e49f9-211a-4976-8c9b-fa710fe0006a\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"724def81-de05-49d7-b35b-ff76bef2ba1c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2734-09-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2325-06-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"748f52e9-b38c-4b11-9b28-36a9d85cde1a\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1358-06-16\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1806-09-03\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2718-10-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"57ab4e63-a38f-4406-9de8-eb36fe23f06f\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1428-10-30\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2420-06-24\",\n \"jurisdiction\": \"ky\",\n \"licenseJurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"56bef94e-f037-48bc-b1b3-6656adcb82d5\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"729f2359-b258-4765-811a-7abfe6875218\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"d64e0125-554f-4387-acf1-d5f6eb2ef76e\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2061-12-04\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2627-11-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"f8897c81-45d4-4745-89fd-9249c67b47cc\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1799-10-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1723-12-04\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2654-12-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"92719762-7632-4c94-910e-0c270bc86bea\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1849-03-03\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"al\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1209-09-09\",\n \"dateOfIssuance\": \"2562-07-21\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"al\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"778440f1-8d4a-4d23-bdf5-b2a67de3dec6\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"de2288d4-6db9-452d-965b-703aa622be6b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"1472f1db-00ca-4f23-a24c-875a06f89120\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2364-08-14\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+0719488777635\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1609-03-01\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1242-04-15\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"bb61587b-7822-4b68-8e5e-879ed5897d5b\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1283-09-19\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2772-02-07\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1525-06-16\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"61a2d3f9-b3b2-457c-8334-eba416548ccc\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2220-04-09\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"2690-10-30\",\n \"dateOfIssuance\": \"2475-10-22\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"a97be73e-996c-4dcb-bf18-99786e09a26e\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"3087ae27-6731-4005-8baa-0d41e992092d\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"cbcf5ee9-4f12-4878-bf24-0407896f902c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1816-11-01\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+41465201\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2383-12-03\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1854-08-10\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"c954fd7c-a8a9-44fd-a27e-6f379cca8c7c\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1007-10-25\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1679-02-03\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2536-04-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"b39d6a11-8ed1-40f5-9876-9a4b9b5b9d23\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1256-11-31\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n }\n ],\n \"total\": {\n \"value\": \"\",\n \"relation\": \"eq\"\n },\n \"lastSort\": \"\"\n}", + "body": "{\n \"providers\": [\n {\n \"birthMonthDay\": \"16-02\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"co\",\n \"licenseStatus\": \"active\",\n \"providerId\": \"983077ef-81b6-4e94-a38d-9ecfda81b86a\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2707-10-31\",\n \"jurisdiction\": \"al\",\n \"licenseJurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"eaa19666-0c94-40e4-a15b-db3ed72c3bb3\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"c45c1eed-682f-40cf-9586-62f4d524c01c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"998f10c3-8571-4c5d-b26c-ba6934198c2b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2034-07-13\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1515-10-28\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3f479d09-990a-4d9a-b7ba-41df74b00041\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2271-10-09\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1699-10-22\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2676-02-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5cbf3e2c-da58-4ee0-b7ce-07dec8207bd6\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2681-04-18\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2987-06-31\",\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"eae111bd-d3b8-448d-b01d-cc797b006fc0\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"e160d703-de3b-49c7-be24-331f6f3c000b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"7fbcb526-c2ec-4d3c-8fd6-3c72870b61d1\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1170-02-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2792-01-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"9afcaf64-67b0-418d-af53-c8096d813948\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2220-01-05\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1220-12-21\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2085-06-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3cea388c-d4dc-45a1-9c48-caecd5433902\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2664-05-20\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"md\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1635-05-30\",\n \"dateOfIssuance\": \"2279-12-06\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"va\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"f5ecbfb0-8245-4dce-bc5c-8e8c3fb720e3\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"1caf7375-85f8-40d4-9d88-1d5bc6478576\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"39eb05fc-2aca-4c31-ba27-24d53ab319f6\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2768-02-20\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+17859210533\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2973-11-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2861-07-13\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"e88c198f-5081-42f4-8f26-fa6e0d3640d0\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2162-03-10\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2915-10-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2600-09-07\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5b0a05f2-b595-44d2-9735-1691df5f2068\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2740-12-31\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1447-08-30\",\n \"dateOfIssuance\": \"2140-11-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"az\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"2a06657c-43d8-4e1f-8cf0-d661da262204\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"8de6cacb-65ea-46b8-9349-f540f70e66ab\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"f66dbdd5-ddbe-4e23-846c-c3b36082da8f\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1091-11-01\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+266910525245\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1801-03-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1899-03-29\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"05c59b30-09dc-484c-a37e-e238db0aa2e1\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1399-02-08\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1949-02-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2961-12-29\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d5c72dd2-df42-47e5-9d12-f2a4b0cf4d33\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2645-06-06\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n },\n {\n \"birthMonthDay\": \"11-31\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"al\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"3c413612-aff7-422f-9ae3-cac05b1d837f\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2530-12-06\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"d9498e8c-9005-4782-b574-6e6cf0e44011\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"76bb1feb-1b15-434e-935d-9be37563997b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"064865aa-71b0-4e48-a07a-6c9a8bbdbd76\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1336-06-14\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1196-02-22\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"06dbbb61-3f81-4f45-b6fc-82443c4f419e\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1791-11-14\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1113-10-04\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1083-12-02\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"8d84550a-baec-4842-a5f8-3d1399b7afda\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2292-10-11\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1226-12-06\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"492f0fcd-f0f4-457f-b8da-7a7ee442bcac\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"7599e0cf-2c34-4f9b-875c-5ab0ca531c4d\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"e2057bce-3488-4ecc-83df-aec735abc462\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1411-09-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1107-02-07\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"088ed538-7672-4dd8-a192-d08bb7129261\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1999-09-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2451-12-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2938-12-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"612dae37-a887-4877-9ee1-c7f9da7e17cf\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1943-03-30\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"al\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1630-06-11\",\n \"dateOfIssuance\": \"2424-03-03\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"md\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"\",\n \"providerId\": \"ac33c991-d600-490c-bfca-5f2caac4f117\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"11cc1dae-f66d-45dd-92a2-fdf7eed8bd86\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"cac6a717-28ed-4398-8e70-bdb956bf8ee3\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2872-03-09\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+2087609290\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1858-12-25\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1711-12-28\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"346a41e7-21f9-40f3-aa0a-8e6d8693d732\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1776-11-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1142-03-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2399-11-12\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"4f9c5550-7026-4660-ad1c-bb825f4fe36d\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2138-02-26\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1870-01-08\",\n \"dateOfIssuance\": \"2155-09-20\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"\",\n \"providerId\": \"bd51940e-807e-435d-b9fc-00bd6ad6f7bb\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"9cb66796-f7f0-4340-9a03-93b2c4b14093\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"04350816-776b-4cf7-bfbe-48a5d17f5432\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1601-11-31\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+9770350103011\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2894-11-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1672-10-07\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"f1476062-ec15-46b2-a931-50b4cd7cfbf0\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1514-10-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1782-07-01\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1686-05-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"c59cfdee-1dde-4280-9b69-5f7747e9cfa1\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2431-12-31\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n }\n ],\n \"total\": {\n \"value\": \"\",\n \"relation\": \"eq\"\n },\n \"lastSort\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -474,7 +474,7 @@ "value": "application/json" } ], - "id": "c36abece-6005-41ba-be06-62cc97d6fd61", + "id": "9646725c-fe05-4bce-9b1f-3dadb5c4929b", "name": "200 response", "originalRequest": { "body": { diff --git a/backend/cosmetology-app/lambdas/nodejs/package.json b/backend/cosmetology-app/lambdas/nodejs/package.json index 22d753312..652c0ab90 100644 --- a/backend/cosmetology-app/lambdas/nodejs/package.json +++ b/backend/cosmetology-app/lambdas/nodejs/package.json @@ -49,7 +49,7 @@ "@aws-sdk/client-sesv2": "^3.901.0", "@aws-sdk/util-dynamodb": "^3.901.0", "@csg-org/email-builder": "^0.0.12", - "nodemailer": "^7.0.11", + "nodemailer": "^8.0.5", "zod": "^3.23.8" } } diff --git a/backend/cosmetology-app/lambdas/nodejs/yarn.lock b/backend/cosmetology-app/lambdas/nodejs/yarn.lock index 712c9cb92..5c2043be8 100644 --- a/backend/cosmetology-app/lambdas/nodejs/yarn.lock +++ b/backend/cosmetology-app/lambdas/nodejs/yarn.lock @@ -4610,10 +4610,10 @@ node-releases@^2.0.27: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== -nodemailer@^7.0.11: - version "7.0.13" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-7.0.13.tgz#74acaa55f0c6f9476384c29f27f53e467e8483cd" - integrity sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw== +nodemailer@^8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-8.0.5.tgz#2076fb2b5c1ccfe1c88f6e1aa47c0229ea642e0c" + integrity sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w== normalize-path@^3.0.0: version "3.0.0" diff --git a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt index a9830bddb..953aab1d0 100644 --- a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt @@ -6,11 +6,11 @@ # aws-lambda-powertools==3.26.0 # via -r lambdas/python/cognito-backup/requirements-dev.in -boto3==1.42.76 +boto3==1.42.80 # via # -r lambdas/python/cognito-backup/requirements-dev.in # moto -botocore==1.42.76 +botocore==1.42.80 # via # -r lambdas/python/cognito-backup/requirements-dev.in # boto3 @@ -53,7 +53,7 @@ py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi -pygments==2.19.2 +pygments==2.20.0 # via pytest pytest==9.0.2 # via -r lambdas/python/cognito-backup/requirements-dev.in @@ -65,7 +65,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # moto # responses diff --git a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt index d09196eab..4b13b6c88 100644 --- a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt @@ -6,9 +6,9 @@ # aws-lambda-powertools==3.26.0 # via -r lambdas/python/cognito-backup/requirements.in -boto3==1.42.76 +boto3==1.42.80 # via -r lambdas/python/cognito-backup/requirements.in -botocore==1.42.76 +botocore==1.42.80 # via # -r lambdas/python/cognito-backup/requirements.in # boto3 diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py index 0e4db7d86..568e76032 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py @@ -243,3 +243,21 @@ class LicenseOpenSearchDocumentSchema(LicenseGeneralResponseSchema): """ dateOfBirth = Raw(required=False, allow_none=False) + + +class LicensePublicResponseSchema(LicenseExpirationStatusMixin, ForgivingSchema): + """ + License object fields, as seen by the public lookup endpoints. + + Serialization direction: + Python -> load() -> API + """ + + type = String(required=True, allow_none=False) + compact = Compact(required=True, allow_none=False) + jurisdiction = Jurisdiction(required=True, allow_none=False) + licenseType = String(required=True, allow_none=False) + licenseStatus = ActiveInactive(required=True, allow_none=False) + compactEligibility = CompactEligibility(required=True, allow_none=False) + dateOfExpiration = Raw(required=True, allow_none=False) + licenseNumber = String(required=True, allow_none=False, validate=Length(1, 100)) diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/privilege/api.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/privilege/api.py index 375552406..f08f35e0d 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/privilege/api.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/privilege/api.py @@ -4,7 +4,6 @@ from cc_common.data_model.schema.adverse_action.api import ( AdverseActionGeneralResponseSchema, - AdverseActionPublicResponseSchema, ) from cc_common.data_model.schema.base_record import ForgivingSchema from cc_common.data_model.schema.fields import ( @@ -81,6 +80,5 @@ class PrivilegePublicResponseSchema(ForgivingSchema): licenseJurisdiction = Jurisdiction(required=True, allow_none=False) licenseType = String(required=True, allow_none=False) dateOfExpiration = Raw(required=True, allow_none=False) - adverseActions = List(Nested(AdverseActionPublicResponseSchema, required=False, allow_none=False)) administratorSetStatus = ActiveInactive(required=True, allow_none=False) status = ActiveInactive(required=True, allow_none=False) diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py index 76721b20c..52dbdcc2a 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py @@ -15,6 +15,7 @@ from cc_common.data_model.schema.license.api import ( LicenseGeneralResponseSchema, LicenseOpenSearchDocumentSchema, + LicensePublicResponseSchema, LicenseReadPrivateResponseSchema, ) from cc_common.data_model.schema.privilege.api import ( @@ -202,17 +203,30 @@ class ProviderPublicResponseSchema(ForgivingSchema): familyName = String(required=True, allow_none=False, validate=Length(1, 100)) suffix = String(required=False, allow_none=False, validate=Length(1, 100)) - # Unlike the internal provider search endpoints used by staff users, which return license data in addition to - # privilege data for a provider, we only return privilege data for a provider from the public GET provider endpoint + # Unlike the JCC public provider search, which only returns privilege data for a provider, Cosmetology returns both + # licenses and privileges and does not return any adverse action data. + licenses = List(Nested(LicensePublicResponseSchema(), required=False, allow_none=False)) privileges = List(Nested(PrivilegePublicResponseSchema(), required=False, allow_none=False)) - # Note the lack of `licenses` here: we do not return license data for public endpoints + + +class PublicLicenseSearchResponseSchema(ForgivingSchema): + """ + License object fields returned by the public query providers endpoint. + """ + + providerId = Raw(required=True, allow_none=False) + givenName = String(required=True, allow_none=False, validate=Length(1, 100)) + familyName = String(required=True, allow_none=False, validate=Length(1, 100)) + licenseJurisdiction = String(required=True, allow_none=False) + compact = Compact(required=True, allow_none=False) + licenseType = String(required=True, allow_none=False) + licenseNumber = String(required=True, allow_none=False, validate=Length(1, 100)) class QueryProvidersRequestSchema(CCRequestSchema): """ - Schema for query providers requests. + Schema for staff query providers requests. - This schema is used to validate incoming requests to both the staff and public query providers API endpoints. It corresponds to the V1QueryProvidersRequestModel in the API model. Serialization direction: @@ -228,6 +242,7 @@ class QuerySchema(CCRequestSchema): jurisdiction = Jurisdiction(required=False, allow_none=False) givenName = String(required=False, allow_none=False, validate=Length(min=1, max=100)) familyName = String(required=False, allow_none=False, validate=Length(min=1, max=100)) + licenseNumber = String(required=False, allow_none=False, validate=Length(min=1, max=100)) class PaginationSchema(ForgivingSchema): """ @@ -235,7 +250,7 @@ class PaginationSchema(ForgivingSchema): """ lastKey = String(required=False, allow_none=False, validate=Length(min=1, max=1024)) - pageSize = Integer(required=False, allow_none=False) + pageSize = Integer(required=False, allow_none=False, validate=Range(min=5, max=100)) class SortingSchema(ForgivingSchema): """ @@ -250,6 +265,29 @@ class SortingSchema(ForgivingSchema): sorting = Nested(SortingSchema, required=False, allow_none=False) +class PublicQueryProvidersRequestSchema(CCRequestSchema): + """ + Request body for the public POST .../providers/query endpoint only. + + The query object allows only jurisdiction, givenName, familyName, and licenseNumber. + Pagination and sorting match QueryProvidersRequestSchema. + """ + + class PublicQuerySchema(CCRequestSchema): + """ + Nested schema for the query object within the request. + """ + + jurisdiction = Jurisdiction(required=False, allow_none=False) + givenName = String(required=False, allow_none=False, validate=Length(min=1, max=100)) + familyName = String(required=False, allow_none=False, validate=Length(min=1, max=100)) + licenseNumber = String(required=False, allow_none=False, validate=Length(min=1, max=100)) + + query = Nested(PublicQuerySchema, required=True, allow_none=False) + pagination = Nested(QueryProvidersRequestSchema.PaginationSchema, required=False, allow_none=False) + sorting = Nested(QueryProvidersRequestSchema.SortingSchema, required=False, allow_none=False) + + class SearchProvidersRequestSchema(CCRequestSchema): """ Schema for advanced search providers requests. diff --git a/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt index f5cc42655..6b818e51c 100644 --- a/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt @@ -19,15 +19,15 @@ aws-sam-translator==1.103.0 # moto aws-xray-sdk==2.15.0 # via moto -boto3==1.42.76 +boto3==1.42.80 # via # aws-sam-translator # moto -boto3-stubs[full]==1.42.76 +boto3-stubs[full]==1.42.80 # via -r lambdas/python/common/requirements-dev.in -boto3-stubs-full==1.42.76 +boto3-stubs-full==1.42.80 # via boto3-stubs -botocore==1.42.76 +botocore==1.42.80 # via # aws-xray-sdk # boto3 @@ -139,9 +139,9 @@ referencing==0.37.0 # jsonschema-path # jsonschema-specifications # openapi-schema-validator -regex==2026.2.28 +regex==2026.3.32 # via cfn-lint -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/common/requirements.txt b/backend/cosmetology-app/lambdas/python/common/requirements.txt index 80d4acacd..703414a25 100644 --- a/backend/cosmetology-app/lambdas/python/common/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/common/requirements.txt @@ -10,9 +10,9 @@ argon2-cffi-bindings==25.1.0 # via argon2-cffi aws-lambda-powertools==3.26.0 # via -r lambdas/python/common/requirements.in -boto3==1.42.76 +boto3==1.42.80 # via -r lambdas/python/common/requirements.in -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # s3transfer @@ -41,7 +41,7 @@ pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 # via botocore -requests==2.33.0 +requests==2.33.1 # via -r lambdas/python/common/requirements.in s3transfer==0.16.0 # via boto3 diff --git a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py index 1c2028506..d045cbafe 100644 --- a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py +++ b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py @@ -108,6 +108,26 @@ def test_general_response_schema_does_not_include_date_of_birth_in_licenses(self self.assertNotIn('dateOfBirth', result['licenses'][0]) +class TestQueryProvidersRequestSchema(TstLambdas): + """QueryProvidersRequestSchema.QuerySchema licenseNumber length matches API Gateway model (max 100).""" + + def test_query_license_number_accepts_100_chars(self): + from cc_common.data_model.schema.provider.api import QueryProvidersRequestSchema + + ln = 'x' * 100 + body = {'query': {'licenseNumber': ln, 'jurisdiction': 'oh'}} + loaded = QueryProvidersRequestSchema().load(body) + self.assertEqual(ln, loaded['query']['licenseNumber']) + + def test_query_license_number_rejects_over_100_chars(self): + from cc_common.data_model.schema.provider.api import QueryProvidersRequestSchema + + body = {'query': {'licenseNumber': 'x' * 101, 'jurisdiction': 'oh'}} + with self.assertRaises(ValidationError) as ctx: + QueryProvidersRequestSchema().load(body) + self.assertIn('licenseNumber', ctx.exception.messages['query']) + + class TestProviderRecordSchema(TstLambdas): def test_serde(self): """Test round-trip deserialization/serialization""" diff --git a/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt index 18ec47fa2..a5fe8d15f 100644 --- a/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/compact-configuration/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -47,7 +47,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt index 9135054c4..530bcabe2 100644 --- a/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/custom-resources/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -47,7 +47,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt index 6a6828dad..85dc0cb06 100644 --- a/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/data-events/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -47,7 +47,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt index 3acabd513..0a241c3c2 100644 --- a/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/disaster-recovery/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -47,7 +47,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py index 6f4fafdbd..9fa6abd8f 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py @@ -1,115 +1,12 @@ from aws_lambda_powertools.utilities.typing import LambdaContext -from cc_common.config import config, logger -from cc_common.data_model.schema.provider.api import ProviderPublicResponseSchema, QueryProvidersRequestSchema +from cc_common.config import logger +from cc_common.data_model.schema.provider.api import ProviderPublicResponseSchema from cc_common.exceptions import CCInvalidRequestException from cc_common.utils import api_handler -from marshmallow import ValidationError from . import get_provider_information -@api_handler -def public_query_providers(event: dict, context: LambdaContext): # noqa: ARG001 unused-argument - """Query providers data - :param event: Standard API Gateway event, API schema documented in the CDK ApiStack - :param LambdaContext context: - """ - compact = event['pathParameters']['compact'] - - # Parse and validate the request body using the schema to strip whitespace - try: - schema = QueryProvidersRequestSchema() - body = schema.loads(event['body']) - except ValidationError as e: - logger.warning('Invalid request body', errors=e.messages) - raise CCInvalidRequestException(f'Invalid request: {e.messages}') from e - - query = body.get('query', {}) - if 'providerId' in query.keys(): - provider_id = query['providerId'] - query = {'providerId': provider_id} - resp = config.data_client.get_provider( - compact=compact, - provider_id=provider_id, - pagination=body.get('pagination'), - detail=False, - ) - resp['query'] = query - - else: - if 'givenName' in query.keys() and 'familyName' not in query.keys(): - raise CCInvalidRequestException('familyName is required if givenName is provided') - provider_name = None - if 'familyName' in query.keys(): - provider_name = (query.get('familyName'), query.get('givenName')) - - jurisdiction = query.get('jurisdiction') - - if jurisdiction: - # If the request is for a jurisdiction that is not live yet in the compact, - # we return empty results to reduce the number of queries made - # otherwise the request will search through the entire data set - if not config.compact_configuration_client.is_jurisdiction_live_in_compact(compact, jurisdiction): - logger.info( - 'Jurisdiction is not live in compact, returning empty results', - compact=compact, - jurisdiction=jurisdiction, - ) - return { - 'query': query, - 'sorting': body.get('sorting', {}), - 'providers': [], - 'pagination': body.get('pagination', {}), - } - - sorting = body.get('sorting', {}) - sorting_key = sorting.get('key') - - sort_direction = sorting.get('direction', 'ascending') - scan_forward = sort_direction == 'ascending' - - match sorting_key: - case None | 'familyName': - resp = { - 'query': query, - 'sorting': {'key': 'familyName', 'direction': sort_direction}, - **config.data_client.get_providers_sorted_by_family_name( - compact=compact, - jurisdiction=jurisdiction, - provider_name=provider_name, - scan_forward=scan_forward, - pagination=body.get('pagination'), - ), - } - case 'dateOfUpdate': - if provider_name is not None: - raise CCInvalidRequestException( - 'givenName and familyName are not supported for sorting by dateOfUpdate', - ) - resp = { - 'query': query, - 'sorting': {'key': 'dateOfUpdate', 'direction': sort_direction}, - **config.data_client.get_providers_sorted_by_updated( - compact=compact, - jurisdiction=jurisdiction, - scan_forward=scan_forward, - pagination=body.get('pagination'), - ), - } - case _: - # This shouldn't happen unless our api validation gets misconfigured - raise CCInvalidRequestException(f"Invalid sort key: '{sorting_key}'") - # Convert generic field to more specific one for this API and sanitize data - unsanitized_providers = resp.pop('items', []) - # for the public query endpoint, we only return publicly available data - public_schema = ProviderPublicResponseSchema() - sanitized_providers = [public_schema.load(provider) for provider in unsanitized_providers] - - resp['providers'] = sanitized_providers - - return resp - - @api_handler def public_get_provider(event: dict, context: LambdaContext): # noqa: ARG001 unused-argument """Return one provider's data diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt index f6bc9a6f6..996847a2e 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/provider-data-v1/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -49,7 +49,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py index 4eb64442d..d7c72db8f 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py @@ -1,362 +1,12 @@ import json from datetime import datetime from unittest.mock import patch -from urllib.parse import quote from moto import mock_aws from .. import TstFunction -@mock_aws -@patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat('2024-11-08T23:59:59+00:00')) -class TestPublicQueryProviders(TstFunction): - def _when_jurisdiction_is_live_in_compact(self, jurisdiction): - self.test_data_generator.put_default_compact_configuration_in_configuration_table( - value_overrides={ - 'compactAbbr': 'cosm', - 'configuredStates': [{'postalAbbreviation': jurisdiction, 'isLive': True}], - } - ) - - def test_public_query_by_provider_id_returns_public_allowed_fields(self): - self._load_provider_data() - - from handlers.public_lookup import public_query_providers - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps({'query': {'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570'}}) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - with open('../common/tests/resources/api/provider-response.json') as f: - expected_provider = json.load(f) - # we do not return the following fields for the public endpoint - expected_provider.pop('birthMonthDay') - expected_provider.pop('dateOfExpiration') - expected_provider.pop('jurisdictionUploadedLicenseStatus') - expected_provider.pop('jurisdictionUploadedCompactEligibility') - - body = json.loads(resp['body']) - self.assertEqual( - { - 'providers': [expected_provider], - 'pagination': {'pageSize': 100, 'lastKey': None, 'prevLastKey': None}, - 'query': {'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570'}, - }, - body, - ) - - def test_public_query_providers_updated_sorting(self): - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 20 providers with licenses in oh (two batches) - self._generate_providers(home='oh', start_serial=9999) - self._generate_providers(home='oh', start_serial=9899) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps( - {'sorting': {'key': 'dateOfUpdate'}, 'query': {'jurisdiction': 'oh'}, 'pagination': {'pageSize': 10}}, - ) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual(10, len(body['providers'])) - self.assertEqual({'providers', 'pagination', 'query', 'sorting'}, body.keys()) - self.assertIsInstance(body['pagination']['lastKey'], str) - # Check we're actually sorted - dates_of_update = [provider['dateOfUpdate'] for provider in body['providers']] - self.assertListEqual(sorted(dates_of_update), dates_of_update) - - def test_public_query_providers_updated_sorting_returns_providers_with_license_in_jurisdiction(self): - """Tests that the public endpoint returns providers with a license in the requested jurisdiction.""" - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 20 providers with licenses in oh (two batches) - self._generate_providers(home='oh', start_serial=9999) - self._generate_providers(home='oh', start_serial=9899) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps( - {'sorting': {'key': 'dateOfUpdate'}, 'query': {'jurisdiction': 'oh'}, 'pagination': {'pageSize': 20}}, - ) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual(20, len(body['providers'])) - # Check we're actually sorted - dates_of_update = [provider['dateOfUpdate'] for provider in body['providers']] - self.assertListEqual(sorted(dates_of_update), dates_of_update) - - def test_public_query_providers_family_name_sorting(self): - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 20 providers with licenses in oh (two batches); first 10 have challenging name characters - names = [ - ('山田', '1'), - ('後藤', '2'), - ('清水', '3'), - ('近藤', '4'), - ('Anderson', '5'), - ('Bañuelos', '6'), - ('de la Fuente', '7'), - ('Dennis', '8'), - ('Figueroa', '9'), - ('Frías', '10'), - ] - self._generate_providers(home='oh', start_serial=9999, names=names) - self._generate_providers(home='oh', start_serial=9899) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps( - {'sorting': {'key': 'familyName'}, 'query': {'jurisdiction': 'oh'}, 'pagination': {'pageSize': 10}}, - ) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual(10, len(body['providers'])) - self.assertEqual({'providers', 'pagination', 'query', 'sorting'}, body.keys()) - self.assertEqual({'key': 'familyName', 'direction': 'ascending'}, body['sorting']) - self.assertIsInstance(body['pagination']['lastKey'], str) - # Check we're actually sorted - family_names = [provider['familyName'].lower() for provider in body['providers']] - self.assertListEqual(sorted(family_names, key=quote), family_names) - - def test_public_query_providers_by_family_name(self): - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 10 providers with licenses in oh, including Tess and Ted Testerly - self._generate_providers( - home='oh', - start_serial=9999, - names=(('Testerly', 'Tess'), ('Testerly', 'Ted')), - ) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps( - { - 'sorting': {'key': 'familyName'}, - 'query': {'jurisdiction': 'oh', 'familyName': 'Testerly'}, - 'pagination': {'pageSize': 10}, - }, - ) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual(2, len(body['providers'])) - - def test_public_query_returns_empty_results_if_jurisdiction_is_not_live(self): - from handlers.public_lookup import public_query_providers - - # 10 providers from ohio, but ohio is not live in the system, so we should return without querying - # for providers - self._generate_providers( - home='oh', - start_serial=9999, - names=(('Testerly', 'Tess'), ('Testerly', 'Ted')), - ) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps( - { - 'sorting': {'key': 'familyName'}, - 'query': {'jurisdiction': 'oh', 'familyName': 'Testerly'}, - 'pagination': {'pageSize': 10}, - }, - ) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual( - { - 'pagination': {'pageSize': 10}, - 'providers': [], - 'query': {'familyName': 'Testerly', 'jurisdiction': 'oh'}, - 'sorting': {'key': 'familyName'}, - }, - body, - ) - - def test_public_query_providers_given_name_only_not_allowed(self): - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 10 providers with licenses in oh, including Tess and Ted Testerly - self._generate_providers( - home='oh', - start_serial=9999, - names=(('Testerly', 'Tess'), ('Testerly', 'Ted')), - ) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps( - { - 'sorting': {'key': 'familyName'}, - 'query': {'jurisdiction': 'oh', 'givenName': 'Tess'}, - 'pagination': {'pageSize': 10}, - }, - ) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(400, resp['statusCode']) - - def test_query_providers_default_sorting(self): - """If sorting is not specified, familyName is default""" - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 20 providers with licenses (10 in oh, 10 in ne) - self._generate_providers(home='oh', start_serial=9999) - self._generate_providers(home='ne', start_serial=9899) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps({'query': {}}) - - resp = public_query_providers(event, self.mock_context) - - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual(20, len(body['providers'])) - self.assertEqual({'providers', 'pagination', 'query', 'sorting'}, body.keys()) - self.assertEqual({'key': 'familyName', 'direction': 'ascending'}, body['sorting']) - self.assertIsNone(body['pagination']['lastKey']) - # Check we're actually sorted - family_names = [provider['familyName'].lower() for provider in body['providers']] - self.assertListEqual(sorted(family_names, key=quote), family_names) - - def test_public_query_providers_invalid_sorting(self): - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # 20 providers with licenses (10 in oh, 10 in ne) - self._generate_providers(home='oh', start_serial=9999) - self._generate_providers(home='ne', start_serial=9899) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - event['body'] = json.dumps({'query': {'jurisdiction': 'oh'}, 'sorting': {'key': 'invalid'}}) - - resp = public_query_providers(event, self.mock_context) - - # Should reject the query, with 400 - self.assertEqual(400, resp['statusCode']) - - def test_public_query_providers_strips_whitespace_from_query_fields(self): - """Test that whitespace is stripped from multiple fields simultaneously.""" - from handlers.public_lookup import public_query_providers - - self._when_jurisdiction_is_live_in_compact(jurisdiction='oh') - - # Create providers with known names for testing - self._generate_providers( - home='oh', - start_serial=9999, - names=(('Testerly', 'Tess'), ('Testerly', 'Ted')), - ) - - with open('../common/tests/resources/api-event.json') as f: - event = json.load(f) - - # public endpoint does not have authorizer - del event['requestContext']['authorizer'] - event['pathParameters'] = {'compact': 'cosm'} - - # Test multiple fields with whitespace - event['body'] = json.dumps( - { - 'query': { - 'givenName': ' Ted ', - 'familyName': ' Testerly ', - 'jurisdiction': ' oh ', - }, - 'pagination': {'pageSize': 10}, - } - ) - - resp = public_query_providers(event, self.mock_context) - self.assertEqual(200, resp['statusCode']) - - body = json.loads(resp['body']) - self.assertEqual(1, len(body['providers'])) # Should find Ted Testerly - found_provider = body['providers'][0] - self.assertEqual('Ted', found_provider['givenName']) - self.assertEqual('Testerly', found_provider['familyName']) - - @mock_aws @patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat('2024-11-08T23:59:59+00:00')) class TestPublicGetProvider(TstFunction): @@ -364,13 +14,6 @@ def setUp(self): super().setUp() self.set_live_compact_jurisdictions_for_test({'cosm': ['ne']}) - @staticmethod - def _get_sensitive_hash(): - with open('../common/tests/resources/dynamo/license-update.json') as f: - sk = json.load(f)['sk'] - # The actual sensitive part is the hash at the end of the key - return sk.split('/')[-1] - def test_public_get_provider_response_with_expected_fields_filtered(self): self._load_provider_data() @@ -389,26 +32,47 @@ def test_public_get_provider_response_with_expected_fields_filtered(self): self.assertEqual(200, resp['statusCode']) provider_data = json.loads(resp['body']) - with open('../common/tests/resources/api/provider-detail-response.json') as f: - expected_provider = json.load(f) - # we do not return the following fields from the public endpoint - expected_provider.pop('ssnLastFour') - expected_provider.pop('dateOfBirth') - expected_provider.pop('birthMonthDay') - expected_provider.pop('licenses') - expected_provider['privileges'][0].pop('investigations') - expected_provider.pop('dateOfExpiration') - expected_provider.pop('jurisdictionUploadedLicenseStatus') - expected_provider.pop('jurisdictionUploadedCompactEligibility') + # ProviderPublicResponseSchema + LicensePublicResponseSchema + PrivilegePublicResponseSchema + expected_provider = { + 'type': 'provider', + 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', + 'dateOfUpdate': '2024-07-08T23:59:59+00:00', + 'compact': 'cosm', + 'licenseJurisdiction': 'oh', + 'licenseStatus': 'active', + 'compactEligibility': 'eligible', + 'givenName': 'Björk', + 'middleName': 'Gunnar', + 'familyName': 'Guðmundsdóttir', + 'licenses': [ + { + 'type': 'license', + 'compact': 'cosm', + 'jurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'licenseStatus': 'active', + 'compactEligibility': 'eligible', + 'dateOfExpiration': '2025-04-04', + 'licenseNumber': 'A0608337260', + } + ], + 'privileges': [ + { + 'type': 'privilege', + 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', + 'compact': 'cosm', + 'jurisdiction': 'ne', + 'licenseJurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'dateOfExpiration': '2025-04-04', + 'administratorSetStatus': 'active', + 'status': 'active', + } + ], + } self.assertEqual(expected_provider, provider_data) - # The sk for a license-update record is sensitive so we'll do an extra, pretty broad, check just to make sure - # we guard against future changes that might accidentally send the key out via the API. See discussion on - # key generation in the LicenseUpdateRecordSchema for details. - sensitive_hash = self._get_sensitive_hash() - self.assertNotIn(sensitive_hash, resp['body']) - def test_public_get_provider_missing_provider_id(self): from handlers.public_lookup import public_get_provider diff --git a/backend/cosmetology-app/lambdas/python/search/handlers/manage_opensearch_indices.py b/backend/cosmetology-app/lambdas/python/search/handlers/manage_opensearch_indices.py index 0c606ba4d..d707ac1fb 100644 --- a/backend/cosmetology-app/lambdas/python/search/handlers/manage_opensearch_indices.py +++ b/backend/cosmetology-app/lambdas/python/search/handlers/manage_opensearch_indices.py @@ -3,10 +3,7 @@ from cc_common.config import config, logger from cc_common.exceptions import CCInternalException from custom_resource_handler import CustomResourceHandler, CustomResourceResponse -from opensearch_client import OpenSearchClient - -# Initial index version for new deployments -INITIAL_INDEX_VERSION = 'v1' +from opensearch_client import INITIAL_INDEX_VERSION, OpenSearchClient # Readiness check configuration # OpenSearch domains may take time to become responsive after CloudFormation reports them as created. @@ -53,8 +50,7 @@ def on_create(self, properties: dict) -> CustomResourceResponse | None: index_name = f'compact_{compact}_providers_{INITIAL_INDEX_VERSION}' # Create alias name (e.g., compact_cosm_providers) alias_name = f'compact_{compact}_providers' - self._create_provider_index_with_alias( - client=client, + client.create_provider_index_with_alias( index_name=index_name, alias_name=alias_name, number_of_shards=number_of_shards, @@ -144,215 +140,5 @@ def _wait_for_domain_ready(self) -> OpenSearchClient: f'Last error: {last_exception}' ) - def _create_provider_index_with_alias( - self, - client: OpenSearchClient, - index_name: str, - alias_name: str, - number_of_shards: int, - number_of_replicas: int, - ) -> None: - """ - Create the provider index and alias in OpenSearch if they don't exist. - - :param client: The OpenSearch client - :param index_name: The versioned index name (e.g., compact_cosm_providers_v1) - :param alias_name: The alias name (e.g., compact_cosm_providers) - :param number_of_shards: Number of primary shards for the index - :param number_of_replicas: Number of replica shards for the index - """ - # Check if the alias already exists (meaning an index version is already set up) - if client.alias_exists(alias_name): - logger.info(f"Alias '{alias_name}' already exists. Skipping index and alias creation.") - return - - # Check if the index already exists (edge case: index exists but alias doesn't) - if client.index_exists(index_name): - logger.info(f"Index '{index_name}' already exists. Creating alias only.") - client.create_alias(index_name, alias_name) - logger.info(f"Alias '{alias_name}' -> '{index_name}' created successfully.") - return - - # Create the index with the specified configuration - logger.info(f"Creating index '{index_name}'...") - index_mapping = self._get_provider_index_mapping(number_of_shards, number_of_replicas) - client.create_index(index_name, index_mapping) - logger.info(f"Index '{index_name}' created successfully.") - - # Create the alias pointing to the new index - logger.info(f"Creating alias '{alias_name}' -> '{index_name}'...") - client.create_alias(index_name, alias_name) - logger.info(f"Alias '{alias_name}' -> '{index_name}' created successfully.") - - def _get_provider_index_mapping(self, number_of_shards: int, number_of_replicas: int) -> dict: - """ - Define the index mapping for provider documents. - - :param number_of_shards: Number of primary shards for the index - :param number_of_replicas: Number of replica shards for the index - :return: The index mapping dictionary - """ - # Nested schema for AdverseAction - adverse_action_properties = { - 'type': {'type': 'keyword'}, - 'adverseActionId': {'type': 'keyword'}, - 'compact': {'type': 'keyword'}, - 'jurisdiction': {'type': 'keyword'}, - 'providerId': {'type': 'keyword'}, - 'licenseType': {'type': 'keyword'}, - 'licenseTypeAbbreviation': {'type': 'keyword'}, - 'actionAgainst': {'type': 'keyword'}, - 'effectiveStartDate': {'type': 'date'}, - 'creationDate': {'type': 'date'}, - 'effectiveLiftDate': {'type': 'date'}, - 'dateOfUpdate': {'type': 'date'}, - 'encumbranceType': {'type': 'keyword'}, - 'clinicalPrivilegeActionCategories': {'type': 'keyword'}, - 'clinicalPrivilegeActionCategory': {'type': 'keyword'}, - 'submittingUser': {'type': 'keyword'}, - 'liftingUser': {'type': 'keyword'}, - } - - # Nested schema for Investigation - investigation_properties = { - 'type': {'type': 'keyword'}, - 'investigationId': {'type': 'keyword'}, - 'compact': {'type': 'keyword'}, - 'jurisdiction': {'type': 'keyword'}, - 'licenseType': {'type': 'keyword'}, - 'status': {'type': 'keyword'}, - 'dateOfUpdate': {'type': 'date'}, - } - - # Nested schema for License - license_properties = { - 'providerId': {'type': 'keyword'}, - 'type': {'type': 'keyword'}, - 'dateOfUpdate': {'type': 'date'}, - 'compact': {'type': 'keyword'}, - 'jurisdiction': {'type': 'keyword'}, - 'licenseType': {'type': 'keyword'}, - 'licenseStatusName': {'type': 'keyword'}, - 'licenseStatus': {'type': 'keyword'}, - 'jurisdictionUploadedLicenseStatus': {'type': 'keyword'}, - 'compactEligibility': {'type': 'keyword'}, - 'jurisdictionUploadedCompactEligibility': {'type': 'keyword'}, - 'licenseNumber': {'type': 'keyword'}, - 'givenName': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'middleName': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'familyName': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'suffix': {'type': 'keyword'}, - 'dateOfIssuance': {'type': 'date'}, - 'dateOfRenewal': {'type': 'date'}, - 'dateOfExpiration': {'type': 'date'}, - 'dateOfBirth': {'type': 'date'}, - 'homeAddressStreet1': {'type': 'text'}, - 'homeAddressStreet2': {'type': 'text'}, - 'homeAddressCity': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'homeAddressState': {'type': 'keyword'}, - 'homeAddressPostalCode': {'type': 'keyword'}, - 'emailAddress': {'type': 'keyword'}, - 'phoneNumber': {'type': 'keyword'}, - 'adverseActions': {'type': 'nested', 'properties': adverse_action_properties}, - 'investigations': {'type': 'nested', 'properties': investigation_properties}, - 'investigationStatus': {'type': 'keyword'}, - } - - # Nested schema for Privilege - privilege_properties = { - 'type': {'type': 'keyword'}, - 'providerId': {'type': 'keyword'}, - 'compact': {'type': 'keyword'}, - 'jurisdiction': {'type': 'keyword'}, - 'licenseJurisdiction': {'type': 'keyword'}, - 'licenseType': {'type': 'keyword'}, - 'dateOfIssuance': {'type': 'date'}, - 'dateOfRenewal': {'type': 'date'}, - 'dateOfExpiration': {'type': 'date'}, - 'dateOfUpdate': {'type': 'date'}, - 'adverseActions': {'type': 'nested', 'properties': adverse_action_properties}, - 'investigations': {'type': 'nested', 'properties': investigation_properties}, - 'administratorSetStatus': {'type': 'keyword'}, - 'compactTransactionId': {'type': 'keyword'}, - 'privilegeId': {'type': 'keyword'}, - 'status': {'type': 'keyword'}, - 'investigationStatus': {'type': 'keyword'}, - } - - return { - 'settings': { - 'index': { - 'number_of_shards': number_of_shards, - 'number_of_replicas': number_of_replicas, - }, - 'analysis': { - # this custom analyzer is recommended by Opensearch when you have international character - # sets, and you want to support searching by their closest ASCII equivalents. - # See https://docs.opensearch.org/latest/analyzers/token-filters/asciifolding/ - 'filter': {'custom_ascii_folding': {'type': 'asciifolding', 'preserve_original': True}}, - 'analyzer': { - 'custom_ascii_analyzer': { - 'type': 'custom', - 'tokenizer': 'standard', - 'filter': ['lowercase', 'custom_ascii_folding'], - } - }, - }, - }, - 'mappings': { - 'properties': { - # Top-level provider fields - 'providerId': {'type': 'keyword'}, - 'type': {'type': 'keyword'}, - 'dateOfUpdate': {'type': 'date'}, - 'compact': {'type': 'keyword'}, - 'licenseJurisdiction': {'type': 'keyword'}, - 'licenseStatus': {'type': 'keyword'}, - 'compactEligibility': {'type': 'keyword'}, - 'givenName': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'middleName': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'familyName': { - 'type': 'text', - 'analyzer': 'custom_ascii_analyzer', - 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, - }, - 'suffix': {'type': 'keyword'}, - 'dateOfExpiration': {'type': 'date'}, - 'jurisdictionUploadedLicenseStatus': {'type': 'keyword'}, - 'jurisdictionUploadedCompactEligibility': {'type': 'keyword'}, - 'providerFamGivMid': {'type': 'keyword'}, - 'providerDateOfUpdate': {'type': 'date'}, - 'birthMonthDay': {'type': 'keyword'}, - # Nested arrays - 'licenses': {'type': 'nested', 'properties': license_properties}, - 'privileges': {'type': 'nested', 'properties': privilege_properties}, - } - }, - } - on_event = OpenSearchIndexManager('opensearch-index-manager') diff --git a/backend/cosmetology-app/lambdas/python/search/handlers/populate_provider_documents.py b/backend/cosmetology-app/lambdas/python/search/handlers/populate_provider_documents.py index b4904f24b..30b35f0a1 100644 --- a/backend/cosmetology-app/lambdas/python/search/handlers/populate_provider_documents.py +++ b/backend/cosmetology-app/lambdas/python/search/handlers/populate_provider_documents.py @@ -19,6 +19,14 @@ "startingLastKey": {"pk": "...", "sk": "..."} } +Optional parameters: + +- resetIndexes: If true, deletes and recreates all compact provider indexes before + indexing (uses numberOfShards / numberOfReplicas). Run during low traffic; do not + combine with resumption (startingCompact / startingLastKey) for the same run. +- numberOfShards: Primary shard count for recreated indexes (default: 1). +- numberOfReplicas: Replica shard count for recreated indexes (default: 0). + Race Condition Consideration: A potential race condition can occur when running this function while provider data is being actively updated: @@ -33,13 +41,23 @@ low traffic. Given that it is a one-time process to initially populate the table, the risk is low and if needed, this Lambda function can be run again to synchronize all the provider documents. + +Note that the resetIndexes parameter is intended for development environments +due to a limitation with how OpenSearch will randomly drop your data nodes if +you only have 1 in your cluster. If the OpenSearch Domain drops that node due +to network failures, aliases and indices will be lost and if the ingest pipeline +inserts records before the aliases are recreated, OpenSearch will automatically +create those indices under the alias name, but without the proper index mapping +which will break our search endpoints. This reset functionality allows devs in +test environments to reset those aliases/indices into a clean state before +populating all the provider records. """ from aws_lambda_powertools.utilities.typing import LambdaContext from cc_common.config import config, logger from cc_common.exceptions import CCInternalException from marshmallow import ValidationError -from opensearch_client import OpenSearchClient +from opensearch_client import INITIAL_INDEX_VERSION, OpenSearchClient from utils import generate_provider_opensearch_documents # Batch size for DynamoDB pagination @@ -64,12 +82,40 @@ def populate_provider_documents(event: dict, context: LambdaContext): :param event: Lambda event with optional parameters: - startingCompact: The compact to start/resume processing from - startingLastKey: The DynamoDB pagination key to resume from + - resetIndexes: If true, delete and recreate all compact indexes first + - numberOfShards: Shards for recreated indexes (default 1) + - numberOfReplicas: Replicas for recreated indexes (default 0) :param context: Lambda context :return: Summary of indexing operation, including pagination info if incomplete """ data_client = config.data_client opensearch_client = OpenSearchClient() + reset_indexes = bool(event.get('resetIndexes', False)) + number_of_shards = int(event.get('numberOfShards', 1)) + number_of_replicas = int(event.get('numberOfReplicas', 0)) + + if reset_indexes: + # this reset functionality is only intended for development environments + if config.environment_name == 'prod': + raise CCInternalException('resetIndexes is not supported in production environments') + logger.info( + 'resetIndexes=True: deleting and recreating all compact indexes', + number_of_shards=number_of_shards, + number_of_replicas=number_of_replicas, + ) + for compact in config.compacts: + alias_name = f'compact_{compact}_providers' + index_name = f'compact_{compact}_providers_{INITIAL_INDEX_VERSION}' + opensearch_client.delete_provider_index_with_alias(alias_name=alias_name) + opensearch_client.create_provider_index_with_alias( + index_name=index_name, + alias_name=alias_name, + number_of_shards=number_of_shards, + number_of_replicas=number_of_replicas, + ) + logger.info('Index reset complete. Proceeding with population.') + # Get optional pagination parameters from event for resumption (normal mode) starting_compact = event.get('startingCompact') starting_last_key = event.get('startingLastKey') diff --git a/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py b/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py new file mode 100644 index 000000000..80e173c13 --- /dev/null +++ b/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py @@ -0,0 +1,225 @@ +import json +from base64 import b64decode, b64encode + +from aws_lambda_powertools.utilities.typing import LambdaContext +from cc_common.config import config, logger +from cc_common.data_model.schema.provider.api import ( + PublicLicenseSearchResponseSchema, + PublicQueryProvidersRequestSchema, +) +from cc_common.exceptions import CCInvalidRequestException +from cc_common.utils import api_handler +from marshmallow import ValidationError +from opensearch_client import OpenSearchClient + +# Instantiate the OpenSearch client outside the handler to cache the connection between invocations +# Set timeout to 20 seconds to give API gateway time to respond with response +opensearch_client = OpenSearchClient(timeout=20) + + +@api_handler +def public_search_api_handler(event: dict, context: LambdaContext): # noqa: ARG001 unused-argument + """ + Public query providers endpoint (no auth). + Translates structured query (licenseNumber, familyName, givenName, jurisdiction) into OpenSearch + nested query and returns license-level results with existing pagination schema. + + Indexing is one OpenSearch document per license; each hit maps to one license row. + """ + http_method = event.get('httpMethod') + resource_path = event.get('resource') + if (http_method, resource_path) != ('POST', '/v1/public/compacts/{compact}/providers/query'): + raise CCInvalidRequestException(f'Unsupported method or resource: {http_method} {resource_path}') + + return _public_query_licenses(event, context) + + +def _public_query_licenses(event: dict, context: LambdaContext): # noqa: ARG001 unused-argument + path_params = event.get('pathParameters') or {} + compact_raw = path_params.get('compact') + compact = _normalize_and_validate_compact_path_parameter(compact_raw) + + body = _parse_and_validate_public_query_body(event) + query_obj = body.get('query', {}) + pagination = body.get('pagination') or {} + page_size = pagination.get('pageSize') or config.default_page_size + + cursor = _decode_public_cursor(pagination.get('lastKey')) + search_body = _build_public_license_search_body(compact=compact, body=body, cursor=cursor) + index_name = f'compact_{compact}_providers' + + logger.info('Executing public license search', compact=compact, index_name=index_name) + response = opensearch_client.search(index_name=index_name, body=search_body) + + hits = response.get('hits', {}).get('hits', []) + license_schema = PublicLicenseSearchResponseSchema() + providers = [] + + for hit in hits: + source = hit.get('_source', {}) + provider_id = source.get('providerId') + if source.get('compact') != compact: + logger.warning( + 'Provider compact does not match path, skipping', + provider_id=provider_id, + path_compact=compact, + ) + continue + licenses = source.get('licenses') or [] + if not licenses: + logger.warning('OpenSearch hit has no licenses array', provider_id=provider_id) + continue + license_fields = licenses[0].copy() + license_fields['providerId'] = source['providerId'] + license_fields['compact'] = source['compact'] + license_fields['givenName'] = source['givenName'] + license_fields['familyName'] = source['familyName'] + try: + # home state is stored under the 'jurisdiction' field on the license record, but + # the frontend expects this to be labeled 'licenseJurisdiction' for parity with other + # public search response schemas. + license_fields['licenseJurisdiction'] = license_fields.pop('jurisdiction', None) + sanitized = license_schema.load(license_fields) + providers.append(sanitized) + except ValidationError as e: + logger.error( + 'Failed to sanitize license record', + provider_id=provider_id, + errors=e.messages, + ) + + last_sort = hits[-1].get('sort') if hits else None + # Full page from OpenSearch => may have more results; use last hit's sort values for search_after + last_key = None + if last_sort is not None and len(hits) >= page_size: + last_key = _encode_public_cursor(last_sort) + + sorting = body.get('sorting') or {} + resolved_sort_key = sorting.get('key') or 'familyName' + resolved_direction = sorting.get('direction') or 'ascending' + + return { + 'providers': providers, + 'pagination': { + 'pageSize': page_size, + 'lastKey': last_key, + 'prevLastKey': pagination.get('lastKey'), + }, + 'query': query_obj, + 'sorting': {'key': resolved_sort_key, 'direction': resolved_direction}, + } + + +def _normalize_and_validate_compact_path_parameter(compact_raw: str | None) -> str: + """ + Strip and case-fold path compact for lookup; return the canonical value from config.compacts. + Rejects missing or unsupported values at the API boundary (400). + """ + if compact_raw is None or not str(compact_raw).strip(): + raise CCInvalidRequestException('Invalid or missing compact') + standardized_compact = str(compact_raw).lower().strip() + if standardized_compact not in config.compacts: + logger.info('Invalid compact provided in path parameter.', compact_path_parameter=standardized_compact) + raise CCInvalidRequestException('Unsupported compact') + return standardized_compact + + +def _parse_and_validate_public_query_body(event: dict) -> dict: + try: + schema = PublicQueryProvidersRequestSchema() + raw_body = event.get('body') or '{}' + body = schema.loads(raw_body) + except ValidationError as e: + logger.warning('Invalid public query request body', errors=e.messages) + raise CCInvalidRequestException(f'Invalid request: {e.messages}') from e + + return body + + +def _decode_public_cursor(last_key: str | None) -> dict | None: + """ + Decode and validate the public cursor (base64 JSON with search_after list). + Raises CCInvalidRequestException if lastKey is present but invalid. + """ + if not last_key: + return None + try: + decoded = json.loads(b64decode(last_key).decode('utf-8')) + except Exception as e: + raise CCInvalidRequestException('Invalid lastKey') from e + if not isinstance(decoded, dict): + raise CCInvalidRequestException('Invalid lastKey') + search_after = decoded.get('search_after') + if not isinstance(search_after, list) or len(search_after) == 0: + raise CCInvalidRequestException('Invalid lastKey') + return {'search_after': search_after} + + +def _encode_public_cursor(search_after: list) -> str: + payload = {'search_after': search_after} + return b64encode(json.dumps(payload).encode('utf-8')).decode('utf-8') + + +def _build_public_opensearch_sort(body: dict) -> list: + """ + Map API sorting (familyName | dateOfUpdate, ascending | descending) to OpenSearch sort clauses. + Uses top-level dateOfUpdate for date sort; _id ascending is always the final tiebreaker. + """ + sorting = body.get('sorting') or {} + sort_key = sorting.get('key') or 'familyName' + sort_direction = sorting.get('direction', 'ascending') + os_dir = 'asc' if sort_direction == 'ascending' else 'desc' + + match sort_key: + case 'familyName': + return [ + # we use nested sorting for familyName and givenName because the top level field is associated + # with the most recent issued license record, which if multiple licenses are issued for the same + # provider, the familyName and givenName may be different between the licenses. + {'licenses.familyName.keyword': {'order': os_dir, 'nested': {'path': 'licenses'}}}, + {'licenses.givenName.keyword': {'order': os_dir, 'nested': {'path': 'licenses'}}}, + {'providerId': os_dir}, + {'_id': 'asc'}, + ] + case 'dateOfUpdate': + return [ + {'dateOfUpdate': os_dir}, + {'_id': 'asc'}, + ] + case _: + raise CCInvalidRequestException(f"Invalid sort key: '{sort_key}'") + + +def _build_public_license_search_body(*, compact: str, body: dict, cursor: dict | None = None) -> dict: + query_obj = body.get('query', {}) + pagination = body.get('pagination') or {} + page_size = pagination.get('pageSize') or config.default_page_size + + search_after = cursor.get('search_after') if cursor else None + + nested_must = [] + if query_obj.get('licenseNumber'): + nested_must.append({'term': {'licenses.licenseNumber': query_obj['licenseNumber']}}) + if query_obj.get('jurisdiction'): + nested_must.append({'term': {'licenses.jurisdiction': query_obj['jurisdiction'].lower()}}) + if query_obj.get('familyName'): + nested_must.append({'match': {'licenses.familyName': query_obj['familyName']}}) + if query_obj.get('givenName'): + nested_must.append({'match': {'licenses.givenName': query_obj['givenName']}}) + + nested_query = {'nested': {'path': 'licenses', 'query': {'bool': {'must': nested_must}}}} + + must = [ + {'term': {'compact': compact}}, + nested_query, + ] + + search_body = { + 'query': {'bool': {'must': must}}, + 'size': page_size, + 'sort': _build_public_opensearch_sort(body), + } + if search_after is not None: + search_body['search_after'] = search_after + + return search_body diff --git a/backend/cosmetology-app/lambdas/python/search/opensearch_client.py b/backend/cosmetology-app/lambdas/python/search/opensearch_client.py index 166c4c740..945f15912 100644 --- a/backend/cosmetology-app/lambdas/python/search/opensearch_client.py +++ b/backend/cosmetology-app/lambdas/python/search/opensearch_client.py @@ -4,10 +4,13 @@ from cc_common.config import config, logger from cc_common.exceptions import CCInternalException, CCInvalidRequestException from opensearchpy import AWSV4SignerAuth, OpenSearch, RequestsHttpConnection -from opensearchpy.exceptions import ConnectionTimeout, RequestError, TransportError +from opensearchpy.exceptions import ConnectionTimeout, NotFoundError, RequestError, TransportError # Retry configuration for operations MAX_RETRY_ATTEMPTS = 5 + +# Initial index version for new deployments (must stay in sync with index naming in handlers) +INITIAL_INDEX_VERSION = 'v1' INITIAL_BACKOFF_SECONDS = 2 MAX_BACKOFF_SECONDS = 32 @@ -80,6 +83,291 @@ def create_alias(self, index_name: str, alias_name: str) -> None: operation_name=f'create_alias({alias_name} -> {index_name})', ) + def get_indices_for_alias(self, alias_name: str) -> list[str]: + """ + Return index names that the given alias points to. + + :param alias_name: The alias name to resolve + :return: List of concrete index names, or empty if the alias does not exist + """ + last_exception = None + backoff_seconds = INITIAL_BACKOFF_SECONDS + + for attempt in range(1, MAX_RETRY_ATTEMPTS + 1): + try: + response = self._client.indices.get_alias(name=alias_name) + return list(response.keys()) + except NotFoundError: + return [] + except (ConnectionTimeout, TransportError) as e: + last_exception = e + if attempt < MAX_RETRY_ATTEMPTS: + logger.warning( + 'Operation failed, retrying with backoff', + operation=f'get_indices_for_alias({alias_name})', + attempt=attempt, + max_attempts=MAX_RETRY_ATTEMPTS, + backoff_seconds=backoff_seconds, + error=str(e), + ) + time.sleep(backoff_seconds) + backoff_seconds = min(backoff_seconds * 2, MAX_BACKOFF_SECONDS) + else: + logger.error( + 'Operation failed after max retry attempts', + operation=f'get_indices_for_alias({alias_name})', + attempts=MAX_RETRY_ATTEMPTS, + error=str(e), + ) + + raise CCInternalException( + f'get_indices_for_alias({alias_name}) failed after {MAX_RETRY_ATTEMPTS} attempts. ' + f'Last error: {last_exception}' + ) + + def delete_index(self, index_name: str) -> None: + """ + Delete an index by name. Deleting an index removes any aliases to it. + + :param index_name: The index to delete + :raises CCInternalException: If all retry attempts fail + """ + self._execute_with_retry( + operation=lambda: self._client.indices.delete(index=index_name), + operation_name=f'delete_index({index_name})', + ) + + def create_provider_index_with_alias( + self, + index_name: str, + alias_name: str, + number_of_shards: int, + number_of_replicas: int, + ) -> None: + """ + Create the provider index and alias in OpenSearch if they don't exist. + + :param index_name: The versioned index name (e.g., compact_cosm_providers_v1) + :param alias_name: The alias name (e.g., compact_cosm_providers) + :param number_of_shards: Number of primary shards for the index + :param number_of_replicas: Number of replica shards for the index + """ + if self.alias_exists(alias_name): + logger.info(f"Alias '{alias_name}' already exists. Skipping index and alias creation.") + return + # Check if an index exists with the same name as the alias (this is most likely to happen in our development + # environments with only one data node. If the test OpenSearch Domain drops that node due to network failures + # aliases and indices will be lost and if the ingest pipeline inserts records before the aliases are recreated, + # OpenSearch will automatically create those indices under the alias name). + if self.index_exists(alias_name): + logger.info(f"Found index with alias name '{alias_name}'; deleting to allow alias creation...") + self.delete_index(alias_name) + logger.info(f"Index '{alias_name}' deleted.") + + if self.index_exists(index_name): + logger.info(f"Index '{index_name}' already exists. Creating alias only.") + self.create_alias(index_name, alias_name) + logger.info(f"Alias '{alias_name}' -> '{index_name}' created successfully.") + return + + logger.info(f"Creating index '{index_name}'...") + index_mapping = self._get_provider_index_mapping(number_of_shards, number_of_replicas) + self.create_index(index_name, index_mapping) + logger.info(f"Index '{index_name}' created successfully.") + + logger.info(f"Creating alias '{alias_name}' -> '{index_name}'...") + self.create_alias(index_name, alias_name) + logger.info(f"Alias '{alias_name}' -> '{index_name}' created successfully.") + + def delete_provider_index_with_alias(self, alias_name: str) -> None: + """ + Delete the versioned index (and its alias) for a provider index alias. + + Resolves underlying indices via the alias, then deletes them. If no alias + exists, attempts to delete the canonical versioned index name + ({alias_name}_{INITIAL_INDEX_VERSION}). + + :param alias_name: The alias name (e.g., compact_cosm_providers) + """ + if self.alias_exists(alias_name): + indices = self.get_indices_for_alias(alias_name) + for idx_name in indices: + logger.info(f"Deleting index '{idx_name}' (via alias '{alias_name}')...") + self.delete_index(idx_name) + logger.info(f"Index '{idx_name}' deleted.") + return + + versioned_index_name = f'{alias_name}_{INITIAL_INDEX_VERSION}' + if self.index_exists(versioned_index_name): + logger.info(f"No alias found; deleting index '{versioned_index_name}' directly...") + self.delete_index(versioned_index_name) + logger.info(f"Index '{versioned_index_name}' deleted.") + else: + logger.info(f"No alias or index found for '{alias_name}'. Nothing to delete.") + + def _get_provider_index_mapping(self, number_of_shards: int, number_of_replicas: int) -> dict: + """ + Define the index mapping for provider documents. + + :param number_of_shards: Number of primary shards for the index + :param number_of_replicas: Number of replica shards for the index + :return: The index mapping dictionary + """ + adverse_action_properties = { + 'type': {'type': 'keyword'}, + 'adverseActionId': {'type': 'keyword'}, + 'compact': {'type': 'keyword'}, + 'jurisdiction': {'type': 'keyword'}, + 'providerId': {'type': 'keyword'}, + 'licenseType': {'type': 'keyword'}, + 'licenseTypeAbbreviation': {'type': 'keyword'}, + 'actionAgainst': {'type': 'keyword'}, + 'effectiveStartDate': {'type': 'date'}, + 'creationDate': {'type': 'date'}, + 'effectiveLiftDate': {'type': 'date'}, + 'dateOfUpdate': {'type': 'date'}, + 'encumbranceType': {'type': 'keyword'}, + 'clinicalPrivilegeActionCategories': {'type': 'keyword'}, + 'clinicalPrivilegeActionCategory': {'type': 'keyword'}, + 'submittingUser': {'type': 'keyword'}, + 'liftingUser': {'type': 'keyword'}, + } + + investigation_properties = { + 'type': {'type': 'keyword'}, + 'investigationId': {'type': 'keyword'}, + 'compact': {'type': 'keyword'}, + 'jurisdiction': {'type': 'keyword'}, + 'licenseType': {'type': 'keyword'}, + 'status': {'type': 'keyword'}, + 'dateOfUpdate': {'type': 'date'}, + } + + license_properties = { + 'providerId': {'type': 'keyword'}, + 'type': {'type': 'keyword'}, + 'dateOfUpdate': {'type': 'date'}, + 'compact': {'type': 'keyword'}, + 'jurisdiction': {'type': 'keyword'}, + 'licenseType': {'type': 'keyword'}, + 'licenseStatusName': {'type': 'keyword'}, + 'licenseStatus': {'type': 'keyword'}, + 'jurisdictionUploadedLicenseStatus': {'type': 'keyword'}, + 'compactEligibility': {'type': 'keyword'}, + 'jurisdictionUploadedCompactEligibility': {'type': 'keyword'}, + 'licenseNumber': {'type': 'keyword'}, + 'givenName': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'middleName': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'familyName': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'suffix': {'type': 'keyword'}, + 'dateOfIssuance': {'type': 'date'}, + 'dateOfRenewal': {'type': 'date'}, + 'dateOfExpiration': {'type': 'date'}, + 'dateOfBirth': {'type': 'date'}, + 'homeAddressStreet1': {'type': 'text'}, + 'homeAddressStreet2': {'type': 'text'}, + 'homeAddressCity': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'homeAddressState': {'type': 'keyword'}, + 'homeAddressPostalCode': {'type': 'keyword'}, + 'emailAddress': {'type': 'keyword'}, + 'phoneNumber': {'type': 'keyword'}, + 'adverseActions': {'type': 'nested', 'properties': adverse_action_properties}, + 'investigations': {'type': 'nested', 'properties': investigation_properties}, + 'investigationStatus': {'type': 'keyword'}, + } + + privilege_properties = { + 'type': {'type': 'keyword'}, + 'providerId': {'type': 'keyword'}, + 'compact': {'type': 'keyword'}, + 'jurisdiction': {'type': 'keyword'}, + 'licenseJurisdiction': {'type': 'keyword'}, + 'licenseType': {'type': 'keyword'}, + 'dateOfIssuance': {'type': 'date'}, + 'dateOfRenewal': {'type': 'date'}, + 'dateOfExpiration': {'type': 'date'}, + 'dateOfUpdate': {'type': 'date'}, + 'adverseActions': {'type': 'nested', 'properties': adverse_action_properties}, + 'investigations': {'type': 'nested', 'properties': investigation_properties}, + 'administratorSetStatus': {'type': 'keyword'}, + 'compactTransactionId': {'type': 'keyword'}, + 'privilegeId': {'type': 'keyword'}, + 'status': {'type': 'keyword'}, + 'investigationStatus': {'type': 'keyword'}, + } + + return { + 'settings': { + 'index': { + 'number_of_shards': number_of_shards, + 'number_of_replicas': number_of_replicas, + }, + 'analysis': { + # Recommended by OpenSearch for international character sets; supports ASCII equivalents. + # See https://docs.opensearch.org/latest/analyzers/token-filters/asciifolding/ + 'filter': {'custom_ascii_folding': {'type': 'asciifolding', 'preserve_original': True}}, + 'analyzer': { + 'custom_ascii_analyzer': { + 'type': 'custom', + 'tokenizer': 'standard', + 'filter': ['lowercase', 'custom_ascii_folding'], + } + }, + }, + }, + 'mappings': { + 'properties': { + 'providerId': {'type': 'keyword'}, + 'type': {'type': 'keyword'}, + 'dateOfUpdate': {'type': 'date'}, + 'compact': {'type': 'keyword'}, + 'licenseJurisdiction': {'type': 'keyword'}, + 'licenseStatus': {'type': 'keyword'}, + 'compactEligibility': {'type': 'keyword'}, + 'givenName': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'middleName': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'familyName': { + 'type': 'text', + 'analyzer': 'custom_ascii_analyzer', + 'fields': {'keyword': {'type': 'keyword', 'ignore_above': 256}}, + }, + 'suffix': {'type': 'keyword'}, + 'dateOfExpiration': {'type': 'date'}, + 'jurisdictionUploadedLicenseStatus': {'type': 'keyword'}, + 'jurisdictionUploadedCompactEligibility': {'type': 'keyword'}, + 'providerFamGivMid': {'type': 'keyword'}, + 'providerDateOfUpdate': {'type': 'date'}, + 'birthMonthDay': {'type': 'keyword'}, + 'licenses': {'type': 'nested', 'properties': license_properties}, + 'privileges': {'type': 'nested', 'properties': privilege_properties}, + } + }, + } + def cluster_health(self) -> dict: """ Get the cluster health status. diff --git a/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt index 73d1914a4..5eb8e15ec 100644 --- a/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/search/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -45,7 +45,7 @@ python-dateutil==2.9.0.post0 # moto pyyaml==6.0.3 # via responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/search/requirements.txt b/backend/cosmetology-app/lambdas/python/search/requirements.txt index 444c4079f..807497ef2 100644 --- a/backend/cosmetology-app/lambdas/python/search/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/search/requirements.txt @@ -12,7 +12,7 @@ charset-normalizer==3.4.6 # via requests events==0.5 # via opensearch-py -grpcio==1.78.0 +grpcio==1.80.0 # via opensearch-protobufs idna==3.11 # via requests @@ -24,7 +24,7 @@ protobuf==7.34.1 # via opensearch-protobufs python-dateutil==2.9.0.post0 # via opensearch-py -requests==2.33.0 +requests==2.33.1 # via opensearch-py six==1.17.0 # via python-dateutil diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py index 36fde869a..0b9593263 100644 --- a/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py @@ -67,6 +67,25 @@ def _when_testing_mock_opensearch_client( else: mock_client_instance.index_exists.return_value = index_exists_return_value + # We want to make assertions on the opensearch client calls that are made during index creation + # to ensure the alias/indices are created with the expected mapping (see the assertions made in the + # test_on_create_creates_versioned_indices_and_aliases_for_all_compacts_when_none_exist test). + # This setup points the mock to the actual function pointers in the opensearch_client client so that + # we are not mocking the methods that set the index mapping. + from opensearch_client import OpenSearchClient + + def _real_get_mapping(number_of_shards, number_of_replicas): + return OpenSearchClient._get_provider_index_mapping( # noqa: SLF001 private-member-access + mock_client_instance, number_of_shards, number_of_replicas + ) + + mock_client_instance._get_provider_index_mapping = _real_get_mapping # noqa: SLF001 private-member-access + + def _real_create_provider_index(*args, **kwargs): + return OpenSearchClient.create_provider_index_with_alias(mock_client_instance, *args, **kwargs) + + mock_client_instance.create_provider_index_with_alias.side_effect = _real_create_provider_index + return mock_client_instance @patch('handlers.manage_opensearch_indices.OpenSearchClient') @@ -363,8 +382,9 @@ def test_on_create_creates_alias_only_when_index_exists_but_alias_does_not(self, # Assert that alias_exists was called for each compact self.assertEqual(1, mock_client_instance.alias_exists.call_count) - # Assert that index_exists was called for each compact - self.assertEqual(1, mock_client_instance.index_exists.call_count) + # Assert that index_exists was called for each compact, and to check if an index was misconfigured + # under the alias name + self.assertEqual(2, mock_client_instance.index_exists.call_count) # Assert that create_index was NOT called since indices already exist mock_client_instance.create_index.assert_not_called() diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py new file mode 100644 index 000000000..512bb8d5b --- /dev/null +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py @@ -0,0 +1,526 @@ +import json +from unittest.mock import patch + +from moto import mock_aws + +from . import TstFunction + + +@mock_aws +class TestPublicSearchProviders(TstFunction): + """Test suite for public_search_api_handler - public license search via OpenSearch.""" + + def setUp(self): + super().setUp() + + def _create_public_api_event(self, compact: str, body: dict = None) -> dict: + """Create API Gateway event for public query providers (no auth).""" + return { + 'resource': '/v1/public/compacts/{compact}/providers/query', + 'path': f'/v1/public/compacts/{compact}/providers/query', + 'httpMethod': 'POST', + 'headers': {'accept': 'application/json', 'content-type': 'application/json'}, + 'multiValueHeaders': {}, + 'queryStringParameters': None, + 'pathParameters': {'compact': compact}, + 'requestContext': { + 'httpMethod': 'POST', + 'resourcePath': '/v1/public/compacts/{compact}/providers/query', + }, + 'body': json.dumps(body) if body else None, + 'isBase64Encoded': False, + } + + def _create_mock_hit( + self, + provider_id: str = '00000000-0000-0000-0000-000000000001', + compact: str = 'cosm', + jurisdiction: str = 'oh', + license_number: str = 'LN123', + family_name: str = 'Doe', + given_name: str = 'John', + sort_values: list = None, + license_type: str = 'cosmetologist', + ) -> dict: + """Create a mock OpenSearch hit for one document per license.""" + doc_id = f'{provider_id}#{jurisdiction}#{license_type}' + hit = { + '_index': f'compact_{compact}_providers', + '_id': doc_id, + '_source': { + 'providerId': provider_id, + 'compact': compact, + 'givenName': given_name, + 'familyName': family_name, + 'licenses': [ + { + 'jurisdiction': jurisdiction, + 'licenseNumber': license_number, + 'licenseType': license_type, + } + ], + }, + } + if sort_values is not None: + hit['sort'] = sort_values + return hit + + @patch('handlers.public_search.opensearch_client') + def test_license_number_search_builds_nested_query(self, mock_opensearch_client): + """Test that licenseNumber in query builds nested term query on licenses.licenseNumber.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN999'}, 'pagination': {'pageSize': 10}}, + ) + public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertIn('query', call_body) + must = call_body['query']['bool']['must'] + nested = next(m for m in must if 'nested' in m) + self.assertEqual('licenses', nested['nested']['path']) + self.assertNotIn('inner_hits', nested['nested']) + inner_must = nested['nested']['query']['bool']['must'] + self.assertIn({'term': {'licenses.licenseNumber': 'LN999'}}, inner_must) + + @patch('handlers.public_search.opensearch_client') + def test_jurisdiction_and_name_search_builds_nested_query(self, mock_opensearch_client): + """Test that jurisdiction and familyName build correct nested query.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'jurisdiction': 'oh', 'familyName': 'Smith'}, + 'pagination': {'pageSize': 10}, + }, + ) + public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + must = call_body['query']['bool']['must'] + nested = next(m for m in must if 'nested' in m) + self.assertNotIn('inner_hits', nested['nested']) + inner_must = nested['nested']['query']['bool']['must'] + self.assertIn({'term': {'licenses.jurisdiction': 'oh'}}, inner_must) + self.assertTrue(any('licenses.familyName' in str(m) for m in inner_must)) + + @patch('handlers.public_search.opensearch_client') + def test_name_only_search_builds_nested_query(self, mock_opensearch_client): + """Test that familyName only builds nested match on licenses.familyName.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'familyName': 'Jones'}, 'pagination': {'pageSize': 10}}, + ) + public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + must = call_body['query']['bool']['must'] + nested = next(m for m in must if 'nested' in m) + self.assertNotIn('inner_hits', nested['nested']) + inner_must = nested['nested']['query']['bool']['must'] + self.assertTrue(any('familyName' in str(m) for m in inner_must)) + + @patch('handlers.public_search.opensearch_client') + def test_sort_includes_id_tiebreaker(self, mock_opensearch_client): + """OpenSearch sort includes _id as the fourth tiebreaker for deterministic pagination.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'familyName': 'Doe'}, 'pagination': {'pageSize': 10}}, + ) + public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + sort = call_body['sort'] + self.assertEqual(4, len(sort)) + self.assertEqual({'_id': 'asc'}, sort[3]) + + @patch('handlers.public_search.opensearch_client') + def test_default_sort_is_family_name_ascending(self, mock_opensearch_client): + """Without sorting in request, default is familyName ascending; response echoes sorting.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'familyName': 'Doe'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + sort = call_body['sort'] + self.assertEqual(4, len(sort)) + self.assertEqual({'licenses.familyName.keyword': {'order': 'asc', 'nested': {'path': 'licenses'}}}, sort[0]) + self.assertEqual({'licenses.givenName.keyword': {'order': 'asc', 'nested': {'path': 'licenses'}}}, sort[1]) + self.assertEqual({'providerId': 'asc'}, sort[2]) + self.assertEqual({'_id': 'asc'}, sort[3]) + body = json.loads(response['body']) + self.assertEqual( + {'key': 'familyName', 'direction': 'ascending'}, + body['sorting'], + ) + + @patch('handlers.public_search.opensearch_client') + def test_family_name_sort_descending(self, mock_opensearch_client): + """sorting key familyName with descending direction maps to OpenSearch desc on name fields.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'familyName': 'Doe'}, + 'pagination': {'pageSize': 10}, + 'sorting': {'key': 'familyName', 'direction': 'descending'}, + }, + ) + response = public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + sort = call_body['sort'] + self.assertEqual({'licenses.familyName.keyword': {'order': 'desc', 'nested': {'path': 'licenses'}}}, sort[0]) + self.assertEqual({'licenses.givenName.keyword': {'order': 'desc', 'nested': {'path': 'licenses'}}}, sort[1]) + self.assertEqual({'providerId': 'desc'}, sort[2]) + self.assertEqual({'_id': 'asc'}, sort[3]) + body = json.loads(response['body']) + self.assertEqual( + {'key': 'familyName', 'direction': 'descending'}, + body['sorting'], + ) + + @patch('handlers.public_search.opensearch_client') + def test_date_of_update_sort_ascending(self, mock_opensearch_client): + """sorting by dateOfUpdate uses top-level date field and _id tiebreaker.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'licenseNumber': 'LN999'}, + 'pagination': {'pageSize': 10}, + 'sorting': {'key': 'dateOfUpdate', 'direction': 'ascending'}, + }, + ) + response = public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertEqual( + [{'dateOfUpdate': 'asc'}, {'_id': 'asc'}], + call_body['sort'], + ) + body = json.loads(response['body']) + self.assertEqual( + {'key': 'dateOfUpdate', 'direction': 'ascending'}, + body['sorting'], + ) + + @patch('handlers.public_search.opensearch_client') + def test_date_of_update_sort_descending(self, mock_opensearch_client): + """dateOfUpdate descending keeps _id tiebreaker ascending.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'licenseNumber': 'LN999'}, + 'pagination': {'pageSize': 10}, + 'sorting': {'key': 'dateOfUpdate', 'direction': 'descending'}, + }, + ) + public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertEqual( + [{'dateOfUpdate': 'desc'}, {'_id': 'asc'}], + call_body['sort'], + ) + + @patch('handlers.public_search.opensearch_client') + def test_response_always_contains_sorting_field(self, mock_opensearch_client): + """Successful public search responses include sorting with key and direction.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'jurisdiction': 'oh'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(200, response['statusCode']) + body = json.loads(response['body']) + self.assertIn('sorting', body) + self.assertEqual({'key', 'direction'}, set(body['sorting'].keys())) + + @patch('handlers.public_search.opensearch_client') + def test_unsupported_compact_returns_400(self, mock_opensearch_client): + """Path compact not in config.compacts returns 400 and does not call OpenSearch.""" + from handlers.public_search import public_search_api_handler + + event = self._create_public_api_event( + 'not-a-compact', + body={'query': {'familyName': 'Doe'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(400, response['statusCode']) + body = json.loads(response['body']) + self.assertIn('compact', body['message'].lower()) + mock_opensearch_client.search.assert_not_called() + + @patch('handlers.public_search.opensearch_client') + def test_invalid_sort_key_returns_400(self, mock_opensearch_client): + """Unknown sorting.key returns 400.""" + from handlers.public_search import public_search_api_handler + + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'familyName': 'Doe'}, + 'pagination': {'pageSize': 10}, + 'sorting': {'key': 'invalidKey', 'direction': 'ascending'}, + }, + ) + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(400, response['statusCode']) + body = json.loads(response['body']) + self.assertIn('Invalid sort key', body['message']) + mock_opensearch_client.search.assert_not_called() + + @patch('handlers.public_search.opensearch_client') + def test_no_search_criteria_returns_200(self, mock_opensearch_client): + """Test that caller can provide an empty query body and still get a successful response.""" + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + + event = self._create_public_api_event( + 'cosm', + body={'query': {}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(200, response['statusCode']) + body = json.loads(response['body']) + self.assertEqual( + { + 'pagination': {'lastKey': None, 'pageSize': 10, 'prevLastKey': None}, + 'providers': [], + 'query': {}, + 'sorting': {'direction': 'ascending', 'key': 'familyName'}, + }, + body, + ) + + def test_provider_id_in_query_returns_400(self): + """Public query must not accept query.providerId (blocked at schema validation).""" + from handlers.public_search import public_search_api_handler + + event = self._create_public_api_event( + 'cosm', + body={ + 'query': { + 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', + 'familyName': 'Doe', + }, + 'pagination': {'pageSize': 10}, + }, + ) + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(400, response['statusCode']) + body = json.loads(response['body']) + self.assertIn('providerId', body['message']) + + @patch('handlers.public_search.opensearch_client') + def test_pagination_page_size_maps_to_size_and_search_after_from_last_key(self, mock_opensearch_client): + """Test that pageSize maps to size and lastKey decodes to search_after.""" + from base64 import b64encode + + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + last_key_payload = json.dumps({'search_after': ['doe', 'jane', 'uuid-123', 'uuid-123#oh#cosmetologist']}) + last_key_str = b64encode(last_key_payload.encode('utf-8')).decode('utf-8') + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'familyName': 'Doe'}, + 'pagination': {'pageSize': 25, 'lastKey': last_key_str}, + }, + ) + public_search_api_handler(event, self.mock_context) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertEqual(25, call_body['size']) + self.assertEqual( + ['doe', 'jane', 'uuid-123', 'uuid-123#oh#cosmetologist'], + call_body['search_after'], + ) + + @patch('handlers.public_search.opensearch_client') + def test_response_last_key_encodes_last_hit_sort_when_full_page(self, mock_opensearch_client): + """When OpenSearch returns a full page of hits, lastKey encodes search_after from the last hit.""" + from base64 import b64decode + + from handlers.public_search import public_search_api_handler + + mock_hits_full_page = [] + for i in range(5): + sort_i = [ + 'doe', + 'john', + f'00000000-0000-0000-0000-00000000000{i}', + f'00000000-0000-0000-0000-00000000000{i}#oh#cosmetologist', + ] + mock_hits_full_page.append( + self._create_mock_hit( + provider_id=f'00000000-0000-0000-0000-00000000000{i}', + sort_values=sort_i, + ) + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 10, 'relation': 'eq'}, 'hits': mock_hits_full_page}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'familyName': 'Doe'}, 'pagination': {'pageSize': 5}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertIn('lastKey', body['pagination']) + self.assertIsNotNone(body['pagination']['lastKey']) + decoded = json.loads(b64decode(body['pagination']['lastKey']).decode('utf-8')) + self.assertEqual(decoded['search_after'], mock_hits_full_page[-1]['sort']) + + @patch('handlers.public_search.opensearch_client') + def test_response_last_key_null_when_fewer_hits_than_page_size(self, mock_opensearch_client): + """When hit count is below pageSize, there are no more pages and lastKey is null.""" + from handlers.public_search import public_search_api_handler + + single_hit = self._create_mock_hit() + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [single_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'familyName': 'Doe'}, 'pagination': {'pageSize': 100}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertIsNone(body['pagination']['lastKey']) + + @patch('handlers.public_search.opensearch_client') + def test_response_contains_only_allowed_license_fields(self, mock_opensearch_client): + """Test that each item in providers has only expected fields.""" + from handlers.public_search import public_search_api_handler + + mock_hit = self._create_mock_hit() + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN123'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual(len(body['providers']), 1) + provider = body['providers'][0] + allowed = { + 'providerId', + 'givenName', + 'familyName', + 'licenseJurisdiction', + 'compact', + 'licenseType', + 'licenseNumber', + } + self.assertEqual(set(provider.keys()), allowed) + self.assertEqual(provider['licenseJurisdiction'], 'oh') + self.assertEqual(provider['licenseType'], 'cosmetologist') + self.assertEqual(provider['licenseNumber'], 'LN123') + + @patch('handlers.public_search.opensearch_client') + def test_compact_mismatch_filtered_out(self, mock_opensearch_client): + """Test that hits with compact != path compact are not included in results.""" + from handlers.public_search import public_search_api_handler + + mock_hit = self._create_mock_hit(compact='other') + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'familyName': 'Doe'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual(body['providers'], []) + + def test_invalid_request_body_returns_400(self): + """Test that invalid or missing body returns 400.""" + from handlers.public_search import public_search_api_handler + + event = self._create_public_api_event('cosm', body=None) + event['body'] = 'not valid json' + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(400, response['statusCode']) + body = json.loads(response['body']) + self.assertIn('Invalid request', body['message']) + + def test_unsupported_route_returns_400(self): + """Test that wrong method/path returns 400.""" + from handlers.public_search import public_search_api_handler + + event = self._create_public_api_event('cosm', body={'query': {'familyName': 'x'}}) + event['resource'] = '/v1/public/compacts/{compact}/providers/other' + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(400, response['statusCode']) + self.assertIn('Unsupported method or resource', json.loads(response['body'])['message']) + + @patch('handlers.public_search.opensearch_client') + def test_invalid_last_key_format_returns_400(self, mock_opensearch_client): + """Malformed or invalid lastKey must return 400.""" + from base64 import b64encode + + from handlers.public_search import public_search_api_handler + + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'hits': []}, + } + bad_payload = json.dumps({}) + last_key = b64encode(bad_payload.encode('utf-8')).decode('utf-8') + event = self._create_public_api_event( + 'cosm', + body={ + 'query': {'familyName': 'Doe'}, + 'pagination': {'pageSize': 10, 'lastKey': last_key}, + }, + ) + response = public_search_api_handler(event, self.mock_context) + self.assertEqual(response['statusCode'], 400) + body = json.loads(response['body']) + self.assertIn('lastkey', body['message'].lower()) + mock_opensearch_client.search.assert_not_called() diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_search_providers.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_search_providers.py index 7bb957f40..827737264 100644 --- a/backend/cosmetology-app/lambdas/python/search/tests/function/test_search_providers.py +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_search_providers.py @@ -618,9 +618,7 @@ def test_search_with_exists_field_date_of_birth_rejected_without_read_private_sc mock_opensearch_client.search.assert_not_called() @patch('handlers.search.opensearch_client') - def test_search_with_date_of_birth_string_in_list_rejected_without_read_private_scope( - self, mock_opensearch_client - ): + def test_search_with_date_of_birth_string_in_list_rejected_without_read_private_scope(self, mock_opensearch_client): """dateOfBirth as a list element (e.g. multi_match fields) must not bypass readPrivate checks.""" from handlers.search import search_api_handler diff --git a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt index 692c16221..59786812f 100644 --- a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/staff-user-pre-token/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -47,7 +47,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt index 559e40ce2..2091602ec 100644 --- a/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt @@ -4,9 +4,9 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/staff-users/requirements-dev.in # -boto3==1.42.76 +boto3==1.42.80 # via moto -botocore==1.42.76 +botocore==1.42.80 # via # boto3 # moto @@ -53,7 +53,7 @@ pyyaml==6.0.3 # via # moto # responses -requests==2.33.0 +requests==2.33.1 # via # docker # moto diff --git a/backend/cosmetology-app/pipeline/backend_stage.py b/backend/cosmetology-app/pipeline/backend_stage.py index 067ce66d3..982cd1941 100644 --- a/backend/cosmetology-app/pipeline/backend_stage.py +++ b/backend/cosmetology-app/pipeline/backend_stage.py @@ -114,6 +114,18 @@ def __init__( persistent_stack=self.persistent_stack, ) + # Search Persistent Stack - OpenSearch Domain (created before ApiStack for public search wiring) + self.search_persistent_stack = SearchPersistentStack( + self, + 'SearchPersistentStack', + env=environment, + environment_context=environment_context, + standard_tags=standard_tags, + environment_name=environment_name, + vpc_stack=self.vpc_stack, + persistent_stack=self.persistent_stack, + ) + self.api_stack = ApiStack( self, 'APIStack', @@ -123,6 +135,7 @@ def __init__( environment_name=environment_name, persistent_stack=self.persistent_stack, api_lambda_stack=self.api_lambda_stack, + search_persistent_stack=self.search_persistent_stack, ) self.state_api_stack = StateApiStack( @@ -191,18 +204,6 @@ def __init__( standard_tags=standard_tags, ) - # Search Persistent Stack - OpenSearch Domain for advanced provider search - self.search_persistent_stack = SearchPersistentStack( - self, - 'SearchPersistentStack', - env=environment, - environment_context=environment_context, - standard_tags=standard_tags, - environment_name=environment_name, - vpc_stack=self.vpc_stack, - persistent_stack=self.persistent_stack, - ) - self.search_api_stack = SearchApiStack( self, 'SearchAPIStack', diff --git a/backend/cosmetology-app/requirements-dev.txt b/backend/cosmetology-app/requirements-dev.txt index 63d3fee25..497c98fad 100644 --- a/backend/cosmetology-app/requirements-dev.txt +++ b/backend/cosmetology-app/requirements-dev.txt @@ -67,7 +67,7 @@ pluggy==1.6.0 # pytest-cov py-serializable==2.1.0 # via cyclonedx-python-lib -pygments==2.19.2 +pygments==2.20.0 # via # pytest # rich @@ -83,7 +83,7 @@ pytest==9.0.2 # pytest-cov pytest-cov==7.1.0 # via -r requirements-dev.in -requests==2.33.0 +requests==2.33.1 # via # cachecontrol # pip-audit diff --git a/backend/cosmetology-app/requirements.txt b/backend/cosmetology-app/requirements.txt index 2ee69e199..a7600ae4e 100644 --- a/backend/cosmetology-app/requirements.txt +++ b/backend/cosmetology-app/requirements.txt @@ -12,11 +12,11 @@ aws-cdk-asset-awscli-v1==2.2.263 # via aws-cdk-lib aws-cdk-asset-node-proxy-agent-v6==2.1.1 # via aws-cdk-lib -aws-cdk-aws-lambda-python-alpha==2.244.0a0 +aws-cdk-aws-lambda-python-alpha==2.246.0a0 # via -r requirements.in -aws-cdk-cloud-assembly-schema==52.2.0 +aws-cdk-cloud-assembly-schema==53.11.0 # via aws-cdk-lib -aws-cdk-lib==2.244.0 +aws-cdk-lib==2.246.0 # via # -r requirements.in # aws-cdk-aws-lambda-python-alpha diff --git a/backend/cosmetology-app/stacks/api_lambda_stack/public_lookup_api.py b/backend/cosmetology-app/stacks/api_lambda_stack/public_lookup_api.py index c0bad9ccb..8aba98160 100644 --- a/backend/cosmetology-app/stacks/api_lambda_stack/public_lookup_api.py +++ b/backend/cosmetology-app/stacks/api_lambda_stack/public_lookup_api.py @@ -38,6 +38,7 @@ def __init__( env_vars=lambda_environment, data_encryption_key=persistent_stack.shared_encryption_key, provider_table=persistent_stack.provider_table, + compact_configuration_table=persistent_stack.compact_configuration_table, alarm_topic=persistent_stack.alarm_topic, ) api_lambda_stack.log_groups.append(self.get_provider_handler.log_group) @@ -52,12 +53,18 @@ def __init__( ) api_lambda_stack.log_groups.append(self.query_providers_handler.log_group) + # Dummy export to avoid CDK deadly embrace: public query providers now uses + # SearchPersistentStack.public_handler; this lambda is no longer wired to the API. + # TODO: remove this export (and the lambda above) after the stack is deployed to all envs # noqa: FIX002 + stack.export_value(self.query_providers_handler.function_arn) + def _get_provider_handler( self, scope: Construct, env_vars: dict, data_encryption_key: IKey, provider_table: ITable, + compact_configuration_table: ITable, alarm_topic: ITopic, ) -> PythonFunction: stack = Stack.of(scope) @@ -74,6 +81,7 @@ def _get_provider_handler( ) data_encryption_key.grant_decrypt(handler) provider_table.grant_read_data(handler) + compact_configuration_table.grant_read_data(handler) NagSuppressions.add_resource_suppressions_by_path( stack, diff --git a/backend/cosmetology-app/stacks/api_stack/__init__.py b/backend/cosmetology-app/stacks/api_stack/__init__.py index 9488e7064..b9d56c586 100644 --- a/backend/cosmetology-app/stacks/api_stack/__init__.py +++ b/backend/cosmetology-app/stacks/api_stack/__init__.py @@ -5,6 +5,7 @@ from constructs import Construct from stacks import persistent_stack as ps +from stacks import search_persistent_stack as sps from stacks.api_lambda_stack import ApiLambdaStack from .api import LicenseApi @@ -20,6 +21,7 @@ def __init__( environment_context: dict, persistent_stack: ps.PersistentStack, api_lambda_stack: ApiLambdaStack, + search_persistent_stack: sps.SearchPersistentStack, **kwargs, ): super().__init__( @@ -35,5 +37,6 @@ def __init__( security_profile=security_profile, persistent_stack=persistent_stack, api_lambda_stack=api_lambda_stack, + search_persistent_stack=search_persistent_stack, domain_name=self.api_domain_name, ) diff --git a/backend/cosmetology-app/stacks/api_stack/api.py b/backend/cosmetology-app/stacks/api_stack/api.py index 89c98fc03..92df96209 100644 --- a/backend/cosmetology-app/stacks/api_stack/api.py +++ b/backend/cosmetology-app/stacks/api_stack/api.py @@ -6,6 +6,7 @@ from common_constructs.cc_api import CCApi from stacks import persistent_stack as ps +from stacks import search_persistent_stack as sps from stacks.api_lambda_stack import ApiLambdaStack @@ -17,6 +18,7 @@ def __init__( *, persistent_stack: ps.PersistentStack, api_lambda_stack: ApiLambdaStack, + search_persistent_stack: sps.SearchPersistentStack, **kwargs, ): super().__init__( @@ -33,6 +35,7 @@ def __init__( self.root, persistent_stack=persistent_stack, api_lambda_stack=api_lambda_stack, + search_persistent_stack=search_persistent_stack, ) @cached_property diff --git a/backend/cosmetology-app/stacks/api_stack/v1_api/api.py b/backend/cosmetology-app/stacks/api_stack/v1_api/api.py index ccffb7b83..dfd68c188 100644 --- a/backend/cosmetology-app/stacks/api_stack/v1_api/api.py +++ b/backend/cosmetology-app/stacks/api_stack/v1_api/api.py @@ -4,6 +4,7 @@ from aws_cdk.aws_apigateway import AuthorizationType, IResource, MethodOptions from stacks import persistent_stack as ps +from stacks import search_persistent_stack as sps from stacks.api_lambda_stack import ApiLambdaStack from .api_model import ApiModel @@ -23,6 +24,7 @@ def __init__( root: IResource, persistent_stack: ps.PersistentStack, api_lambda_stack: ApiLambdaStack, + search_persistent_stack: sps.SearchPersistentStack, ): super().__init__() from stacks.api_stack.api import LicenseApi @@ -112,6 +114,7 @@ def __init__( resource=self.public_compacts_compact_providers_resource, api_model=self.api_model, api_lambda_stack=api_lambda_stack, + search_persistent_stack=search_persistent_stack, ) # /v1/compacts diff --git a/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py b/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py index 7ad26e463..e4972ccf1 100644 --- a/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py +++ b/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py @@ -110,6 +110,12 @@ def query_providers_request_model(self) -> Model: max_length=100, description='Filter for providers with a family name', ), + 'licenseNumber': JsonSchema( + type=JsonSchemaType.STRING, + min_length=1, + max_length=100, + description='Filter for licenses with a specific license number', + ), }, ), 'pagination': self._pagination_request_schema, @@ -1311,7 +1317,7 @@ def public_query_providers_response_model(self) -> Model: 'providers': JsonSchema( type=JsonSchemaType.ARRAY, max_length=100, - items=self._public_providers_response_schema, + items=self._public_license_search_response_schema, ), 'pagination': self._pagination_response_schema, 'query': JsonSchema( @@ -1337,6 +1343,12 @@ def public_query_providers_response_model(self) -> Model: max_length=100, description='Filter for providers with a family name', ), + 'licenseNumber': JsonSchema( + type=JsonSchemaType.STRING, + min_length=1, + max_length=100, + description='Filter for licenses with a specific license number', + ), }, ), 'sorting': self._sorting_schema, @@ -1397,6 +1409,11 @@ def _public_provider_detailed_response_schema(self): 'familyName', ], properties={ + 'licenses': JsonSchema( + type=JsonSchemaType.ARRAY, + description='Sanitized home-state license rows (LicensePublicResponseSchema)', + items=self._public_license_public_response_schema, + ), 'privileges': JsonSchema( type=JsonSchemaType.ARRAY, items=self._public_privilege_response_schema, @@ -1405,6 +1422,37 @@ def _public_provider_detailed_response_schema(self): }, ) + @property + def _public_license_public_response_schema(self): + """License items in public GET provider responses; mirrors LicensePublicResponseSchema.""" + stack: AppStack = AppStack.of(self.api) + return JsonSchema( + type=JsonSchemaType.OBJECT, + required=[ + 'type', + 'compact', + 'jurisdiction', + 'licenseType', + 'licenseStatus', + 'compactEligibility', + 'dateOfExpiration', + 'licenseNumber', + ], + properties={ + 'type': JsonSchema(type=JsonSchemaType.STRING, enum=['license']), + 'compact': JsonSchema(type=JsonSchemaType.STRING, enum=stack.node.get_context('compacts')), + 'jurisdiction': JsonSchema( + type=JsonSchemaType.STRING, + enum=stack.node.get_context('jurisdictions'), + ), + 'licenseType': JsonSchema(type=JsonSchemaType.STRING, enum=self.stack.license_type_names), + 'licenseStatus': JsonSchema(type=JsonSchemaType.STRING, enum=['active', 'inactive']), + 'compactEligibility': JsonSchema(type=JsonSchemaType.STRING, enum=['eligible', 'ineligible']), + 'dateOfExpiration': JsonSchema(type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT), + 'licenseNumber': JsonSchema(type=JsonSchemaType.STRING, min_length=1, max_length=100), + }, + ) + @property def _public_privilege_response_schema(self): """Schema for public privilege responses""" @@ -1438,111 +1486,6 @@ def _public_privilege_response_schema(self): 'dateOfExpiration': JsonSchema(type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT), 'administratorSetStatus': JsonSchema(type=JsonSchemaType.STRING, enum=['active', 'inactive']), 'status': JsonSchema(type=JsonSchemaType.STRING, enum=['active', 'inactive']), - 'history': JsonSchema( - type=JsonSchemaType.ARRAY, - items=JsonSchema( - type=JsonSchemaType.OBJECT, - required=[ - 'type', - 'updateType', - 'providerId', - 'compact', - 'jurisdiction', - 'licenseType', - 'dateOfUpdate', - 'previous', - 'updatedValues', - ], - properties={ - 'type': JsonSchema(type=JsonSchemaType.STRING, enum=['privilegeUpdate']), - 'updateType': self._update_type_schema, - 'providerId': JsonSchema(type=JsonSchemaType.STRING, pattern=cc_api.UUID4_FORMAT), - 'compact': JsonSchema(type=JsonSchemaType.STRING, enum=stack.node.get_context('compacts')), - 'jurisdiction': JsonSchema( - type=JsonSchemaType.STRING, - enum=stack.node.get_context('jurisdictions'), - ), - 'licenseType': JsonSchema(type=JsonSchemaType.STRING, enum=self.stack.license_type_names), - 'dateOfUpdate': JsonSchema(type=JsonSchemaType.STRING, format='date-time'), - 'previous': JsonSchema( - type=JsonSchemaType.OBJECT, - required=[ - 'administratorSetStatus', - 'dateOfExpiration', - 'licenseJurisdiction', - ], - properties={ - 'administratorSetStatus': JsonSchema( - type=JsonSchemaType.STRING, enum=['active', 'inactive'] - ), - 'dateOfExpiration': JsonSchema( - type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT - ), - 'licenseJurisdiction': JsonSchema( - type=JsonSchemaType.STRING, - enum=stack.node.get_context('jurisdictions'), - ), - }, - ), - 'updatedValues': JsonSchema( - type=JsonSchemaType.OBJECT, - properties={ - 'administratorSetStatus': JsonSchema( - type=JsonSchemaType.STRING, enum=['active', 'inactive'] - ), - 'dateOfExpiration': JsonSchema( - type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT - ), - 'licenseJurisdiction': JsonSchema( - type=JsonSchemaType.STRING, - enum=stack.node.get_context('jurisdictions'), - ), - }, - ), - }, - ), - ), - 'adverseActions': JsonSchema( - type=JsonSchemaType.ARRAY, - items=JsonSchema( - type=JsonSchemaType.OBJECT, - required=[ - 'type', - 'compact', - 'providerId', - 'jurisdiction', - 'licenseTypeAbbreviation', - 'licenseType', - 'actionAgainst', - 'effectiveStartDate', - 'creationDate', - 'adverseActionId', - 'dateOfUpdate', - ], - properties={ - 'type': JsonSchema(type=JsonSchemaType.STRING, enum=['adverseAction']), - 'compact': JsonSchema(type=JsonSchemaType.STRING, enum=stack.node.get_context('compacts')), - 'providerId': JsonSchema(type=JsonSchemaType.STRING, pattern=cc_api.UUID4_FORMAT), - 'jurisdiction': JsonSchema( - type=JsonSchemaType.STRING, enum=stack.node.get_context('jurisdictions') - ), - 'licenseTypeAbbreviation': JsonSchema(type=JsonSchemaType.STRING), - 'licenseType': JsonSchema(type=JsonSchemaType.STRING), - 'actionAgainst': JsonSchema(type=JsonSchemaType.STRING), - 'effectiveStartDate': JsonSchema( - type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT - ), - 'creationDate': JsonSchema( - type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT - ), - 'adverseActionId': JsonSchema(type=JsonSchemaType.STRING), - 'effectiveLiftDate': JsonSchema( - type=JsonSchemaType.STRING, format='date', pattern=cc_api.YMD_FORMAT - ), - 'dateOfUpdate': JsonSchema(type=JsonSchemaType.STRING, format='date-time'), - }, - ), - ), }, ) @@ -1627,6 +1570,37 @@ def provider_registration_request_model(self) -> Model: ) return self.api._v1_provider_registration_request_model + @property + def _public_license_search_response_schema(self): + """Schema for public query providers response""" + stack: AppStack = AppStack.of(self.api) + return JsonSchema( + type=JsonSchemaType.OBJECT, + required=[ + 'providerId', + 'givenName', + 'familyName', + 'licenseJurisdiction', + 'compact', + 'licenseType', + 'licenseNumber', + ], + properties={ + 'providerId': JsonSchema(type=JsonSchemaType.STRING, pattern=cc_api.UUID4_FORMAT), + 'givenName': JsonSchema(type=JsonSchemaType.STRING, min_length=1, max_length=100), + 'familyName': JsonSchema(type=JsonSchemaType.STRING, min_length=1, max_length=100), + 'licenseJurisdiction': JsonSchema( + type=JsonSchemaType.STRING, enum=stack.node.get_context('jurisdictions') + ), + 'compact': JsonSchema(type=JsonSchemaType.STRING, enum=stack.node.get_context('compacts')), + 'licenseType': JsonSchema( + type=JsonSchemaType.STRING, + description='License type or profession designation for this license row', + ), + 'licenseNumber': JsonSchema(type=JsonSchemaType.STRING, min_length=1, max_length=100), + }, + ) + @property def _public_providers_response_schema(self): return JsonSchema( diff --git a/backend/cosmetology-app/stacks/api_stack/v1_api/public_lookup_api.py b/backend/cosmetology-app/stacks/api_stack/v1_api/public_lookup_api.py index dc335b2f4..2c13505d0 100644 --- a/backend/cosmetology-app/stacks/api_stack/v1_api/public_lookup_api.py +++ b/backend/cosmetology-app/stacks/api_stack/v1_api/public_lookup_api.py @@ -5,6 +5,7 @@ from cdk_nag import NagSuppressions from common_constructs.cc_api import CCApi +from stacks import search_persistent_stack as sps from stacks.api_lambda_stack import ApiLambdaStack from .api_model import ApiModel @@ -17,6 +18,7 @@ def __init__( resource: Resource, api_model: ApiModel, api_lambda_stack: ApiLambdaStack, + search_persistent_stack: sps.SearchPersistentStack, ): super().__init__() @@ -32,9 +34,7 @@ def __init__( 'licenseType' ).add_resource('{licenseType}') - self._add_public_query_providers( - api_lambda_stack=api_lambda_stack, - ) + self._add_public_query_providers(search_persistent_stack=search_persistent_stack) self._add_public_get_provider( api_lambda_stack=api_lambda_stack, ) @@ -73,13 +73,10 @@ def _add_public_get_provider( ], ) - def _add_public_query_providers( - self, - api_lambda_stack: ApiLambdaStack, - ): + def _add_public_query_providers(self, search_persistent_stack: sps.SearchPersistentStack): query_resource = self.resource.add_resource('query') - handler = api_lambda_stack.public_lookup_lambdas.query_providers_handler + handler = search_persistent_stack.search_handler.public_handler public_query_provider_method = query_resource.add_method( 'POST', diff --git a/backend/cosmetology-app/stacks/search_persistent_stack/populate_provider_documents_handler.py b/backend/cosmetology-app/stacks/search_persistent_stack/populate_provider_documents_handler.py index ca78386ee..8f7989a27 100644 --- a/backend/cosmetology-app/stacks/search_persistent_stack/populate_provider_documents_handler.py +++ b/backend/cosmetology-app/stacks/search_persistent_stack/populate_provider_documents_handler.py @@ -47,7 +47,7 @@ def __init__( :param opensearch_domain: The reference to the OpenSearch domain resource :param vpc_stack: The VPC stack :param vpc_subnets: The VPC subnets for Lambda deployment - :param lambda_role: The IAM role for the Lambda function (should have OpenSearch write access) + :param lambda_role: The IAM role for the Lambda function (OpenSearch read/write for indexing and index reset) :param provider_table: The DynamoDB provider table :param compact_configuration_table: The DynamoDB compact configuration table (for live jurisdictions) :param alarm_topic: The SNS topic for alarms @@ -81,8 +81,9 @@ def __init__( alarm_topic=alarm_topic, ) - # Grant the handler write access to the OpenSearch domain - opensearch_domain.grant_write(self.handler) + # Grant read/write HTTP to the domain (same as index manager). resetIndexes and normal indexing need + # HEAD/GET for alias and index existence checks, plus PUT/POST for bulk index and DELETE for index reset. + opensearch_domain.grant_read_write(self.handler) # Grant the handler read access to the provider table and compact configuration table provider_table.grant_read_data(self.handler) @@ -95,9 +96,9 @@ def __init__( [ { 'id': 'AwsSolutions-IAM5', - 'reason': 'The grant_write method requires wildcard permissions on the OpenSearch domain to ' - 'write to indices. This is appropriate for a function that needs to bulk index ' - 'provider documents. The DynamoDB grant_read_data also requires index permissions.', + 'reason': 'The grant_read_write method requires wildcard permissions on the OpenSearch domain to ' + 'create, read, delete, and manage indices and aliases (including optional resetIndexes). This ' + 'matches the index manager custom resource pattern in index_manager.py.', }, ], ) diff --git a/backend/cosmetology-app/stacks/search_persistent_stack/provider_search_domain.py b/backend/cosmetology-app/stacks/search_persistent_stack/provider_search_domain.py index 3a6ee2aaa..785c407b3 100644 --- a/backend/cosmetology-app/stacks/search_persistent_stack/provider_search_domain.py +++ b/backend/cosmetology-app/stacks/search_persistent_stack/provider_search_domain.py @@ -68,7 +68,7 @@ def __init__( :param vpc_stack: The VPC stack containing network resources :param compact_abbreviations: List of compact abbreviations for index access policies :param alarm_topic: The SNS topic for capacity alarms - :param ingest_lambda_role: IAM role for the ingest Lambda function (write access) + :param ingest_lambda_role: IAM role for ingest and populate-provider Lambdas (OpenSearch read/write on indices) :param index_manager_lambda_role: IAM role for the index manager Lambda function (read/write access) :param search_api_lambda_role: IAM role for the search API Lambda function (read access) """ @@ -211,7 +211,9 @@ def __init__( # Grant lambda roles access to domain self.domain.grant_read(self._search_api_lambda_role) - self.domain.grant_write(self._ingest_lambda_role) + # Ingest role is shared by stream ingest and populate-provider; populate resetIndexes needs GET/HEAD/DELETE + # on indices/aliases in addition to POST/PUT (see ingest_access_policy). + self.domain.grant_read_write(self._ingest_lambda_role) self.domain.grant_read_write(self._index_manager_lambda_role) # Add CDK Nag suppressions @@ -229,7 +231,7 @@ def _configure_access_policies(self, compact_abbreviations: list[str]): Configure access policies for the OpenSearch domain. Creates IAM-based access policies that restrict access to specific Lambda roles: - - Ingest role: POST/PUT access to compact indices + - Ingest role: GET/HEAD/POST/PUT/DELETE on compact indices (bulk ingest, alias/index checks, index reset) - Index manager role: GET/HEAD/POST/PUT access for index management - Search API role: POST access restricted to _search endpoint only @@ -239,8 +241,11 @@ def _configure_access_policies(self, compact_abbreviations: list[str]): effect=Effect.ALLOW, principals=[self._ingest_lambda_role], actions=[ + 'es:ESHttpGet', + 'es:ESHttpHead', 'es:ESHttpPost', 'es:ESHttpPut', + 'es:ESHttpDelete', ], resources=[Fn.join('', [self.domain.domain_arn, '/compact*'])], ) diff --git a/backend/cosmetology-app/stacks/search_persistent_stack/search_handler.py b/backend/cosmetology-app/stacks/search_persistent_stack/search_handler.py index 798083649..5c8ac3538 100644 --- a/backend/cosmetology-app/stacks/search_persistent_stack/search_handler.py +++ b/backend/cosmetology-app/stacks/search_persistent_stack/search_handler.py @@ -76,6 +76,53 @@ def __init__( alarm_topic=alarm_topic, ) + # Create Lambda function for public query providers + self.public_handler = PythonFunction( + self, + 'PublicSearchProvidersFunction', + description='Public search handler for OpenSearch license queries', + index=os.path.join('handlers', 'public_search.py'), + lambda_dir='search', + handler='public_search_api_handler', + role=lambda_role, + log_retention=RetentionDays.ONE_MONTH, + environment={ + 'OPENSEARCH_HOST_ENDPOINT': opensearch_domain.domain_endpoint, + **stack.common_env_vars, + }, + timeout=Duration.seconds(29), + memory_size=2048, + vpc=vpc_stack.vpc, + vpc_subnets=vpc_subnets, + security_groups=[vpc_stack.lambda_security_group], + alarm_topic=alarm_topic, + ) + opensearch_domain.grant_read(self.public_handler) + + # Create metric filter and alarm for public handler errors + public_error_log_metric = MetricFilter( + self, + 'PublicSearchHandlerErrorLogMetric', + log_group=self.public_handler.log_group, + metric_namespace='CompactConnect/Search', + metric_name='PublicSearchHandlerErrors', + filter_pattern=FilterPattern.string_value(json_field='$.level', comparison='=', value='ERROR'), + metric_value='1', + default_value=0, + ) + public_error_log_alarm = Alarm( + self, + 'PublicSearchHandlerErrorLogAlarm', + metric=public_error_log_metric.metric(statistic='Sum'), + evaluation_periods=1, + threshold=1, + actions_enabled=True, + alarm_description='The Public Search Handler Lambda logged an ERROR level message.', + comparison_operator=ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, + treat_missing_data=TreatMissingData.NOT_BREACHING, + ) + public_error_log_alarm.add_alarm_action(SnsAction(alarm_topic)) + # Grant the handler read access to the OpenSearch domain opensearch_domain.grant_read(self.handler) diff --git a/backend/cosmetology-app/tests/app/test_api/test_public_lookup_api.py b/backend/cosmetology-app/tests/app/test_api/test_public_lookup_api.py index 045f40ede..d19a17616 100644 --- a/backend/cosmetology-app/tests/app/test_api/test_public_lookup_api.py +++ b/backend/cosmetology-app/tests/app/test_api/test_public_lookup_api.py @@ -85,8 +85,8 @@ def test_synth_generates_public_query_providers_endpoint(self): """Test that the POST /providers/query endpoint is configured correctly.""" api_stack = self.app.sandbox_backend_stage.api_stack api_stack_template = Template.from_stack(api_stack) - api_lambda_stack = self.app.sandbox_backend_stage.api_lambda_stack - api_lambda_stack_template = Template.from_stack(api_lambda_stack) + search_persistent_stack = self.app.sandbox_backend_stage.search_persistent_stack + search_persistent_stack_template = Template.from_stack(search_persistent_stack) # Ensure the resource is created with expected path api_stack_template.has_resource_properties( @@ -102,13 +102,13 @@ def test_synth_generates_public_query_providers_endpoint(self): # Ensure the lambda is created with expected code path in the ApiLambdaStack query_handler = TestApi.get_resource_properties_by_logical_id( - api_lambda_stack.get_logical_id( - api_lambda_stack.public_lookup_lambdas.query_providers_handler.node.default_child + search_persistent_stack.get_logical_id( + search_persistent_stack.search_handler.public_handler.node.default_child ), - api_lambda_stack_template.find_resources(CfnFunction.CFN_RESOURCE_TYPE_NAME), + search_persistent_stack_template.find_resources(CfnFunction.CFN_RESOURCE_TYPE_NAME), ) - self.assertEqual(query_handler['Handler'], 'handlers.public_lookup.public_query_providers') + self.assertEqual(query_handler['Handler'], 'handlers.public_search.public_search_api_handler') # Capture model logical IDs for verification request_model_logical_id_capture = Capture() @@ -120,9 +120,9 @@ def test_synth_generates_public_query_providers_endpoint(self): props={ 'HttpMethod': 'POST', 'Integration': TestApi.generate_expected_integration_object_for_imported_lambda( - api_lambda_stack, - api_lambda_stack_template, - api_lambda_stack.public_lookup_lambdas.query_providers_handler, + search_persistent_stack, + search_persistent_stack_template, + search_persistent_stack.search_handler.public_handler, ), 'RequestModels': { 'application/json': {'Ref': request_model_logical_id_capture}, diff --git a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_GET_PROVIDER_RESPONSE_SCHEMA.json b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_GET_PROVIDER_RESPONSE_SCHEMA.json index 1b7cd6c94..ed852baa7 100644 --- a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_GET_PROVIDER_RESPONSE_SCHEMA.json +++ b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_GET_PROVIDER_RESPONSE_SCHEMA.json @@ -1,5 +1,82 @@ { "properties": { + "licenses": { + "description": "Sanitized home-state license rows (LicensePublicResponseSchema)", + "items": { + "properties": { + "type": { + "enum": [ + "license" + ], + "type": "string" + }, + "compact": { + "enum": [ + "cosm" + ], + "type": "string" + }, + "jurisdiction": { + "enum": [ + "al", + "az", + "co", + "ks", + "ky", + "md", + "oh", + "tn", + "va", + "wa" + ], + "type": "string" + }, + "licenseType": { + "enum": [ + "cosmetologist", + "esthetician" + ], + "type": "string" + }, + "licenseStatus": { + "enum": [ + "active", + "inactive" + ], + "type": "string" + }, + "compactEligibility": { + "enum": [ + "eligible", + "ineligible" + ], + "type": "string" + }, + "dateOfExpiration": { + "format": "date", + "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", + "type": "string" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "type", + "compact", + "jurisdiction", + "licenseType", + "licenseStatus", + "compactEligibility", + "dateOfExpiration", + "licenseNumber" + ], + "type": "object" + }, + "type": "array" + }, "privileges": { "items": { "properties": { @@ -74,232 +151,6 @@ "inactive" ], "type": "string" - }, - "history": { - "items": { - "properties": { - "type": { - "enum": [ - "privilegeUpdate" - ], - "type": "string" - }, - "updateType": { - "enum": [ - "deactivation", - "expiration", - "issuance", - "other", - "renewal", - "encumbrance", - "lifting_encumbrance", - "licenseDeactivation" - ], - "type": "string" - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "compact": { - "enum": [ - "cosm" - ], - "type": "string" - }, - "jurisdiction": { - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ], - "type": "string" - }, - "licenseType": { - "enum": [ - "cosmetologist", - "esthetician" - ], - "type": "string" - }, - "dateOfUpdate": { - "format": "date-time", - "type": "string" - }, - "previous": { - "properties": { - "administratorSetStatus": { - "enum": [ - "active", - "inactive" - ], - "type": "string" - }, - "dateOfExpiration": { - "format": "date", - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string" - }, - "licenseJurisdiction": { - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ], - "type": "string" - } - }, - "required": [ - "administratorSetStatus", - "dateOfExpiration", - "licenseJurisdiction" - ], - "type": "object" - }, - "updatedValues": { - "properties": { - "administratorSetStatus": { - "enum": [ - "active", - "inactive" - ], - "type": "string" - }, - "dateOfExpiration": { - "format": "date", - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string" - }, - "licenseJurisdiction": { - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "type", - "updateType", - "providerId", - "compact", - "jurisdiction", - "licenseType", - "dateOfUpdate", - "previous", - "updatedValues" - ], - "type": "object" - }, - "type": "array" - }, - "adverseActions": { - "items": { - "properties": { - "type": { - "enum": [ - "adverseAction" - ], - "type": "string" - }, - "compact": { - "enum": [ - "cosm" - ], - "type": "string" - }, - "providerId": { - "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", - "type": "string" - }, - "jurisdiction": { - "enum": [ - "al", - "az", - "co", - "ks", - "ky", - "md", - "oh", - "tn", - "va", - "wa" - ], - "type": "string" - }, - "licenseTypeAbbreviation": { - "type": "string" - }, - "licenseType": { - "type": "string" - }, - "actionAgainst": { - "type": "string" - }, - "effectiveStartDate": { - "format": "date", - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string" - }, - "creationDate": { - "format": "date", - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string" - }, - "adverseActionId": { - "type": "string" - }, - "effectiveLiftDate": { - "format": "date", - "pattern": "^[12]{1}[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$", - "type": "string" - }, - "dateOfUpdate": { - "format": "date-time", - "type": "string" - } - }, - "required": [ - "type", - "compact", - "providerId", - "jurisdiction", - "licenseTypeAbbreviation", - "licenseType", - "actionAgainst", - "effectiveStartDate", - "creationDate", - "adverseActionId", - "dateOfUpdate" - ], - "type": "object" - }, - "type": "array" } }, "required": [ diff --git a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_REQUEST_SCHEMA.json b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_REQUEST_SCHEMA.json index 1d3d3eeb7..e6102e020 100644 --- a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_REQUEST_SCHEMA.json +++ b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_REQUEST_SCHEMA.json @@ -35,6 +35,12 @@ "description": "Filter for providers with a family name", "maxLength": 100, "type": "string" + }, + "licenseNumber": { + "description": "Filter for licenses with a specific license number", + "maxLength": 100, + "minLength": 1, + "type": "string" } }, "type": "object" diff --git a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json index 380303be6..4be0803c4 100644 --- a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json +++ b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json @@ -3,12 +3,6 @@ "providers": { "items": { "properties": { - "type": { - "enum": [ - "provider" - ], - "type": "string" - }, "providerId": { "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab]{1}[0-9a-f]{3}-[0-9a-f]{12}", "type": "string" @@ -18,27 +12,11 @@ "minLength": 1, "type": "string" }, - "middleName": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, "familyName": { "maxLength": 100, "minLength": 1, "type": "string" }, - "suffix": { - "maxLength": 100, - "minLength": 1, - "type": "string" - }, - "compact": { - "enum": [ - "cosm" - ], - "type": "string" - }, "licenseJurisdiction": { "enum": [ "al", @@ -54,18 +32,30 @@ ], "type": "string" }, - "dateOfUpdate": { - "format": "date-time", + "compact": { + "enum": [ + "cosm" + ], + "type": "string" + }, + "licenseType": { + "description": "License type or profession designation for this license row", + "type": "string" + }, + "licenseNumber": { + "maxLength": 100, + "minLength": 1, "type": "string" } }, "required": [ - "type", "providerId", "givenName", "familyName", + "licenseJurisdiction", "compact", - "licenseJurisdiction" + "licenseType", + "licenseNumber" ], "type": "object" }, @@ -130,6 +120,12 @@ "description": "Filter for providers with a family name", "maxLength": 100, "type": "string" + }, + "licenseNumber": { + "description": "Filter for licenses with a specific license number", + "maxLength": 100, + "minLength": 1, + "type": "string" } }, "type": "object" diff --git a/backend/cosmetology-app/tests/resources/snapshots/QUERY_PROVIDERS_REQUEST_SCHEMA.json b/backend/cosmetology-app/tests/resources/snapshots/QUERY_PROVIDERS_REQUEST_SCHEMA.json index 1d3d3eeb7..e6102e020 100644 --- a/backend/cosmetology-app/tests/resources/snapshots/QUERY_PROVIDERS_REQUEST_SCHEMA.json +++ b/backend/cosmetology-app/tests/resources/snapshots/QUERY_PROVIDERS_REQUEST_SCHEMA.json @@ -35,6 +35,12 @@ "description": "Filter for providers with a family name", "maxLength": 100, "type": "string" + }, + "licenseNumber": { + "description": "Filter for licenses with a specific license number", + "maxLength": 100, + "minLength": 1, + "type": "string" } }, "type": "object" diff --git a/backend/cosmetology-app/tests/smoke/query_provider_smoke_tests.py b/backend/cosmetology-app/tests/smoke/query_provider_smoke_tests.py deleted file mode 100644 index 8c11e1a3b..000000000 --- a/backend/cosmetology-app/tests/smoke/query_provider_smoke_tests.py +++ /dev/null @@ -1,214 +0,0 @@ -# ruff: noqa: S101 T201 we use asserts and print statements for smoke testing -import json - -import requests -from config import config, logger -from deepdiff import DeepDiff -from smoke_common import ( - SmokeTestFailureException, - call_provider_users_me_endpoint, - create_test_staff_user, - delete_test_staff_user, - get_staff_user_auth_headers, - load_smoke_test_env, -) - -# This script can be run locally to test the Query/Get Provider flow against a sandbox environment of the Compact -# Connect API. It requires that you have a provider user set up in the same compact of the sandbox environment. -# Your sandbox account must also be deployed with the "security_profile": "VULNERABLE" setting in your cdk.context.json -# file, which allows you to log in users using the boto3 Cognito client. - -# The staff user should be created **without** any 'readPrivate' permissions, as this flow is intended to test -# the general provider data retrieval flow. - -# To run this script, create a smoke_tests_env.json file in the same directory as this script using the -# 'smoke_tests_env_example.json' file as a template. - - -TEST_STAFF_USER_EMAIL = 'testStaffUserQuerySmokeTests@smokeTestFakeEmail.com' - - -def get_general_provider_user_data_smoke_test(): - """ - Verifies that a provider record can be fetched from the GET provider users endpoint with private fields sanitized. - - Step 1: Get the provider id of the provider user profile information. - Step 2: The staff user calls the GET provider users endpoint with the provider id. - Step 3: Verify the Provider response matches the profile. - """ - # Step 1: Get the provider id of the provider user profile information. - test_user_profile = call_provider_users_me_endpoint() - provider_id = provider_user_profile['providerId'] - compact = provider_user_profile['compact'] - - # Step 2: The staff user calls the GET provider users endpoint with the provider id. - staff_users_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) - - get_provider_response = requests.get( - url=config.api_base_url + f'/v1/compacts/{compact}/providers/{provider_id}', - headers=staff_users_headers, - timeout=10, - ) - - if get_provider_response.status_code != 200: - raise SmokeTestFailureException(f'Failed to query provider. Response: {get_provider_response.json()}') - logger.info('Received success response from GET endpoint') - - # Step 3: Verify the Provider response matches the profile. - get_provider_general_provider_object = get_provider_response.json() - - # verify the ssn is NOT in the response - if 'ssn' in get_provider_general_provider_object: - raise SmokeTestFailureException(f'unexpected ssn field returned. Response: {get_provider_response.json()}') - - # remove the fields from the user profile that are not in the query response - test_user_profile.pop('ssnLastFour', None) - test_user_profile.pop('dateOfBirth', None) - test_user_profile.pop('encumberedStatus', None) - for provider_license in test_user_profile['licenses']: - provider_license.pop('ssnLastFour', None) - provider_license.pop('dateOfBirth', None) - provider_license.pop('encumberedStatus', None) - for history_event in provider_license['history']: - history_event['previous'].pop('ssnLastFour', None) - history_event['previous'].pop('dateOfBirth', None) - history_event['previous'].pop('encumberedStatus', None) - - if get_provider_general_provider_object != test_user_profile: - formatted_test_user_profile = json.dumps(test_user_profile, sort_keys=True, indent=4) - formatted_get_provider_response = json.dumps(get_provider_general_provider_object, sort_keys=True, indent=4) - logger.error( - 'Provider object does not match the profile.', - provider_profile=formatted_test_user_profile, - get_provider_response=formatted_get_provider_response, - diff=DeepDiff(test_user_profile, get_provider_general_provider_object), - ) - raise SmokeTestFailureException('Get provider object response does not match the profile.') - logger.info('Successfully fetched expected provider records.') - - -def query_provider_user_smoke_test(): - """ - Verifies that a provider record can be queried . - - Step 1: Get the provider id of the provider user profile information. - Step 2: Have the staff user query for that provider using the profile information. - Step 3: Verify the Provider response matches the profile. - """ - - # Step 1: Get the provider id of the provider user profile information. - test_user_profile = call_provider_users_me_endpoint() - provider_id = provider_user_profile['providerId'] - compact = provider_user_profile['compact'] - - # Step 2: Have the staff user query for that provider using the profile information. - staff_users_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) - post_body = {'query': {'providerId': provider_id}} - - post_response = requests.post( - url=config.api_base_url + f'/v1/compacts/{compact}/providers/query', - headers=staff_users_headers, - json=post_body, - timeout=10, - ) - - if post_response.status_code != 200: - raise SmokeTestFailureException(f'Failed to query provider. Response: {post_response.json()}') - logger.info('Received success response from query endpoint') - # Step 3: Verify the Provider response matches the profile. - providers = post_response.json()['providers'] - if not providers: - raise SmokeTestFailureException(f'No providers returned by query. Response: {post_response.json()}') - - provider_object = providers[0] - - # verify the ssn is NOT in the response - if 'ssn' in provider_object: - raise SmokeTestFailureException(f'unexpected ssn field returned. Response: {post_response.json()}') - - # remove the fields from the user profile that are not in the query response - test_user_profile.pop('ssnLastFour', None) - test_user_profile.pop('dateOfBirth', None) - test_user_profile.pop('licenses') - test_user_profile.pop('privileges') - test_user_profile.pop('encumberedStatus', None) - - if provider_object != test_user_profile: - raise SmokeTestFailureException( - f'Provider list object does not match the profile.\n{DeepDiff(test_user_profile, provider_object)}' - ) - - logger.info('Successfully queried expected provider record.') - - -def get_provider_data_with_read_private_access_smoke_test(test_staff_user_id: str): - """ - Verifies that a staff user can read private fields of a provider record if they have the 'readPrivate' permission. - - Step 1: Update the staff user's permissions using the PATCH '/v1/staff-users/me/permissions' endpoint to include - the 'readPrivate' permission. - Step 2: Generate a new token and call the GET provider users endpoint with the new token. - Step 3: Verify the Provider response matches the profile. - """ - - # Step 1: Get the provider user profile information. - test_user_profile = call_provider_users_me_endpoint() - provider_id = provider_user_profile['providerId'] - compact = provider_user_profile['compact'] - # Step 1: Update the staff user's permissions using the PATCH '/v1/staff-users/me/permissions' endpoint. - staff_users_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) - patch_body = {'permissions': {'cosm': {'actions': {'readPrivate': True}}}} - patch_response = requests.patch( - url=config.api_base_url + f'/v1/compacts/{compact}/staff-users/{test_staff_user_id}', - headers=staff_users_headers, - json=patch_body, - timeout=10, - ) - - if patch_response.status_code != 200: - raise SmokeTestFailureException(f'Failed to PATCH staff user permissions. Response: {patch_response.json()}') - logger.info('Successfully updated staff user permissions.') - - # Step 2: Generate a new token and call the GET provider users endpoint with the new token. - staff_users_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) - get_provider_response = requests.get( - url=config.api_base_url + f'/v1/compacts/{compact}/providers/{provider_id}', - headers=staff_users_headers, - timeout=10, - ) - - if get_provider_response.status_code != 200: - raise SmokeTestFailureException(f'Failed to GET staff user. Response: {get_provider_response.json()}') - - logger.info('Received success response from GET endpoint') - - # Step 3: Verify the Provider response matches the profile. - provider_object = get_provider_response.json() - if provider_object != test_user_profile: - raise SmokeTestFailureException( - f'Provider object does not match the profile.\n{DeepDiff(test_user_profile, provider_object)}' - ) - - logger.info('Successfully fetched expected user profile.') - - -if __name__ == '__main__': - load_smoke_test_env() - provider_user_profile = call_provider_users_me_endpoint() - provider_compact = provider_user_profile['compact'] - # ensure the test staff user is in the same compact as the test provider user without 'readPrivate' permissions - test_user_sub = create_test_staff_user( - email=TEST_STAFF_USER_EMAIL, - compact=provider_compact, - jurisdiction='oh', - permissions={'actions': {'admin'}, 'jurisdictions': {'oh': {'write', 'admin'}}}, - ) - try: - get_general_provider_user_data_smoke_test() - query_provider_user_smoke_test() - get_provider_data_with_read_private_access_smoke_test(test_staff_user_id=test_user_sub) - logger.info('Query provider smoke tests passed') - except SmokeTestFailureException as e: - logger.error(f'Query provider smoke tests failed: {str(e)}') - finally: - delete_test_staff_user(TEST_STAFF_USER_EMAIL, user_sub=test_user_sub, compact=provider_compact) diff --git a/backend/cosmetology-app/tests/smoke/rollback_license_upload_smoke_tests.py b/backend/cosmetology-app/tests/smoke/rollback_license_upload_smoke_tests.py index 266a82afc..2c92f4889 100644 --- a/backend/cosmetology-app/tests/smoke/rollback_license_upload_smoke_tests.py +++ b/backend/cosmetology-app/tests/smoke/rollback_license_upload_smoke_tests.py @@ -370,7 +370,6 @@ def create_privilege_for_provider(provider_id: str, compact: str): 'privilegeId': f'{license_type_abbr.upper()}-{privilege_jurisdiction.upper()}-12345', 'administratorSetStatus': 'active', 'compactTransactionId': 'test-transaction-12345', - 'compactTransactionIdGSIPK': f'COMPACT#{compact}#TX#test-transaction-12345#', } config.provider_user_dynamodb_table.put_item(Item=privilege_record)