ЕСОЗ - публічна документація

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

REST API method / Метод REST API (настанова) (remove the link block before publishing the document)

Properties of a REST API method document

Document type

Метод REST API

Document title

[Document status] REST API [Назва методу] [ID методу]

Guideline ID

GUI-0011

Author

@

Document version

1

Document status

DRAFT

Date of creation

ХХ.ХХ.ХХХХ (дата фінальної версії документа – RC або PROD)

Date of update

ХХ.ХХ.ХХХХ (дата зміни версії)

Method API ID

API-010-001-004-0375

Microservices (namespace)

MPI

Component

Master Patient Index

Component ID

COM-010-001

Link на API-специфікацію

https://ehealthmisapi1.docs.apiary.io/#reference/public.-medical-service-provider-integration-layer/person-requests

Resource

{{host}}/api/person_requests

Scope

person_request:write

Protocol type

REST

Request type

POST

Sync/Async

Sync

Public/Private

Public

Purpose

This method is designed to create or update Person Request (as part of the process of creating a Person without a Declaration)

Logic

Patient creation request statuses

Configuration parameters

Invoke Global parameters to get following parameters:

  • phone_number_auth_limit

Check if in table person_authentication_methods  with type = OTP > N, then error 422, such a phone already exists more N times

  • third_person_limit

In table person_auth_methods with type = third_person > N, then error 422

  • person_request_expiration and person_request_term_unit

  • person_with_third_person_limit

  • no_self_auth_age 

cURL example
curl -X GET \
  {:host}/prm/api/global_parameters

Dictionaries

  • GENDER

  • DOCUMENT_TYPE

  • ADDRESS_TYPE

  • COUNTRY

  • SETTLEMENT_TYPE

  • STREET_TYPE

  • PHONE_TYPE

  • AUTHENTICATION_METHOD

  • CONFIDANT_PERSON_TYPE

  • PREFERRED_WAY_COMMUNICATION

  • DOCUMENT_RELATIONSHIP_TYPE

Input parameters

Input parameter

Mandatory

Type

Description

Example

1

composition_id

 M

String ($uuid) (path)

Composition object ID

 89678f60-4cdc-4fe3-ae83-e8b3ebd35c59

2

 

 

 

 

 

Request structure

See on API-specification

 Example
{
  "person": {
    "id": "13001c60-45a0-4b5a-b425-9505e1de18bd",
    "first_name": "Петро",
    "last_name": "Іванов",
    "second_name": "Миколайович",
    "birth_date": "2009-07-05",
    "birth_country": "Україна",
    "birth_settlement": "Вінниця",
    "gender": "MALE",
    "email": "email@example.com",
    "no_tax_id": false,
    "tax_id": "3999869394",
    "secret": "secret",
    "documents": [
      {
        "type": "BIRTH_CERTIFICATE",
        "number": "АА120518",
        "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
        "issued_at": "2017-02-28",
        "expiration_date": "2027-02-28"
      }
    ],
    "addresses": [
      {
        "type": "RESIDENCE",
        "country": "UA",
        "area": "Житомирська",
        "region": "Бердичівський",
        "settlement": "Київ",
        "settlement_type": "CITY",
        "settlement_id": "b075f148",
        "street_type": "STREET",
        "street": "вул. Ніжинська",
        "building": "15",
        "apartment": "23",
        "zip": "02090"
      }
    ],
    "phones": [
      {
        "type": "MOBILE",
        "number": "+380503410870"
      }
    ],
    "authentication_methods": [
      {
        "type": "THIRD_PERSON",
        "phone_number": "+380508887700",
        "value": "c282f8a9-e709-40aa-94b4-dde1402bf4b6",
        "alias": "husband"
      }
    ],
    "unzr": "20090705-00011",
    "emergency_contact": {
      "first_name": "Петро",
      "last_name": "Іванов",
      "second_name": "Миколайович",
      "phones": [
        {
          "type": "MOBILE",
          "number": "+380503410870"
        }
      ]
    },
    "confidant_person": [
      {
        "relation_type": "PRIMARY",
        "first_name": "Петро",
        "last_name": "Іванов",
        "second_name": "Миколайович",
        "birth_date": "1972-10-26",
        "birth_country": "Україна",
        "birth_settlement": "Вінниця",
        "gender": "MALE",
        "tax_id": "2659719350",
        "secret": "secret",
        "unzr": "19900101-00099",
        "preferred_way_communication": "email",
        "documents_person": [
          {
            "type": "PASSPORT",
            "number": "АА120518",
            "expiration_date": "2021-02-28",
            "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
            "issued_at": "2017-02-28"
          }
        ],
        "documents_relationship": [
          {
            "type": "BIRTH_CERTIFICATE",
            "number": "АА120518",
            "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
            "issued_at": "2017-02-28"
          }
        ],
        "phones": [
          {
            "type": "MOBILE",
            "number": "+380503410870"
          }
        ],
        "email": "emaill@example.com"
      }
    ],
    "preferred_way_communication": "email"
  },
  "patient_signed": false,
  "process_disclosure_data_consent": true,
  "authorize_with": "cc949559-5dfe-420f-ac05-065e443b2cc6"
}

Authorize

  1. Verify the validity of access token

    1. Return (401, 'Invalid access token') in case of validation fails

  2. Verify that token is not expired

    1. in case of error - return (401, 'Invalid access token')

  3. Check user scopes in order to perform this action (scope = 'person_request:write')

    • Return (403, 'Your scope does not allow to access this resource. Missing allowances: person_request:write') in case of invalid scope(s)

  4. validate client_id belongs to legal_entity with type in ('MSP', 'OUTPATIENT', 'EMERGENCY', 'PRIMARY_CARE')

    1. Return (401, 'Invalid legal entity type') in case of validation fails

  5. If BLOCK_UNVERIFIED_PARTY_USERS is true, then check party's data match following condition: verification_status != NOT_VERIFIED or (verification_status = NOT_VERIFIED and updated_at <= current_date - UNVERIFIED_PARTY_PERIOD_DAYS_ALLOWED):

    1. in case not match - return 403 ("Access denied. Party is not verified")

  6. If BLOCK_DECEASED_PARTY_USERS is true, check that party is not deceased (party_verification record does not equal to: dracs_death_verification_status = VERIFIED and dracs_death_verification_reason = MANUAL_CONFIRMED):

    1. in case of error - return 403 ("Access denied. Party is deceased")

  7. validate user belongs to employee with type in "Doctor, Specialist, Receptionist, Assistant"

    1. in case error return 409

Headers

Key

Value

Mandatory

Description

Example

1

Content-Type

application/json

Тип контенту

Content-Type:application/json

2

Authorization

Bearer {{access_token}}

Перевірка користувача

Authorization:Bearer {{access_token}}

3

 api-key

 {{secret}}

 

 Секретний ключ

 api-key:{{secret}}

Request data validation

Validate request

Validate request using JSON schema

  • Check presence of extra parameters

    • In case of error - return 422 ('schema does not allow additional properties')

  • Check presence of required parameters

    • In case of error - return 422 ('required property %{property} was not present')

 JSON Schema
{
  "$schema": "http://json-schema.org/person_request/schema#",
  "definitions": {
    "phone": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: PHONE_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^\\+38[0-9]{10}$"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "name": {
      "type": "string",
      "pattern": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[a-zA-ZА-ЯҐЇІЄа-яґїіє0-9№\\\"!\\^\\*)\\]\\[(._-].*$"
    },
    "person_name": {
      "type": "string",
      "pattern": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\-]+(\\s(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\-]+)*$",
      "minLength": 1,
      "maxLength": 255
    },
    "unzr": {
      "type": "string",
      "pattern": "^[0-9]{8}-[0-9]{5}$"
    },
    "tax_id": {
      "type": "string",
      "pattern": "^[0-9]{10}$",
      "minLength": 10,
      "maxLength": 255
    },
    "no_tax_id": {
      "type": "boolean",
      "description": "Status person refused tax_id"
    },
    "gender": {
      "type": "string",
      "description": "Dictionary: GENDER",
      "maxLength": 255
    },
    "address": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: ADDRESS_TYPE"
        },
        "country": {
          "type": "string"
        },
        "area": {
          "$ref": "#/definitions/name"
        },
        "region": {
          "$ref": "#/definitions/name"
        },
        "settlement": {
          "$ref": "#/definitions/name"
        },
        "settlement_type": {
          "type": "string",
          "description": "settlement type Dictionary: SETTLEMENT_TYPE"
        },
        "settlement_id": {
          "type": "string",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
        },
        "street_type": {
          "type": "string",
          "description": "street type Dictionary: STREET_TYPE"
        },
        "street": {
          "$ref": "#/definitions/name"
        },
        "building": {
          "type": "string",
          "pattern": "^[1-9]((?![ЫЪЭЁыъэё])()([А-ЯҐЇІЄа-яґїіє \\/\\'\\-0-9])){0,20}$"
        },
        "apartment": {
          "type": "string"
        },
        "zip": {
          "type": "string",
          "pattern": "^[0-9]{5}$"
        },
        "inserted_by": {
          "type": "string"
        },
        "updated_by": {
          "type": "string"
        },
        "inserted_at": {
          "type": "string"
        },
        "updated_at": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "country",
        "area",
        "settlement",
        "settlement_type",
        "settlement_id",
        "inserted_by",
        "updated_by"
      ],
      "additionalProperties": false
    },
    "series_number_document": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "PASSPORT",
            "COMPLEMENTARY_PROTECTION_CERTIFICATE",
            "REFUGEE_CERTIFICATE",
            "TEMPORARY_CERTIFICATE"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$"
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "number_document": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "BIRTH_CERTIFICATE",
            "TEMPORARY_PASSPORT"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^(?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]+$",
          "minLength": 1,
          "maxLength": 255
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "id_card": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "NATIONAL_ID"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^[0-9]{9}$"
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "document_relationship": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: DOCUMENT_RELATIONSHIP_TYPE",
          "minLength": 1
        },
        "number": {
          "type": "string",
          "minLength": 1
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "person": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": "string"
        },
        "last_name": {
          "type": "string"
        },
        "second_name": {
          "type": "string"
        },
        "birth_date": {
          "type": "string"
        },
        "birth_country": {
          "type": "string"
        },
        "birth_settlement": {
          "type": "string"
        },
        "gender": {
          "enum": [
            "MALE",
            "FEMALE"
          ]
        },
        "email": {
          "type": "string"
        },
        "no_tax_id": {
          "type": "boolean"
        },
        "tax_id": {
          "type": "string"
        },
        "secret": {
          "type": "string"
        },
        "documents": {
          "type": "array"
        },
        "addresses": {
          "type": "array"
        },
        "phones": {
          "type": "array"
        },
        "authentication_methods": {
          "type": "array"
        },
        "unzr": {
          "type": "string"
        },
        "emergency_contact": {
          "type": "object",
          "properties": {
            "first_name": {
              "type": "string"
            },
            "last_name": {
              "type": "string"
            },
            "second_name": {
              "type": "string"
            },
            "phones": {
              "type": "array"
            }
          },
          "required": [
            "first_name",
            "last_name",
            "phones"
          ]
        },
        "confidant_person": {
          "type": "array"
        },
        "preferred_way_communication": {
          "enum": [
            "email",
            "phone"
          ]
        }
      },
      "required": [
        "first_name",
        "last_name",
        "birth_date",
        "birth_country",
        "birth_settlement",
        "gender",
        "no_tax_id",
        "tax_id",
        "secret",
        "documents",
        "addresses",
        "emergency_contact"
      ]
    },
    "patient_signed": {
      "type": "boolean"
    },
    "process_disclosure_data_consent": {
      "type": "boolean"
    }
  },
  "required": [
    "person",
    "patient_signed",
    "process_disclosure_data_consent"
  ]
}

Validate confidant person

  • Verify that person age < prm.global_parameters.no_self_auth_age check existence of confidant_person

    • Return (422, 'Confidant person is mandatory for children') in case of validation fails

  • Validate confidant person age >= prm.global_parameters.no_self_auth_age

    • Return (422, 'Incorrect person age for such an action') in case of validation fails

Validate "tax_id"

  • tax_id has validation pattern - `^[0-9]{10}$`

    • if doesn't match, return error 422 "string does not match pattern ..."

Check "no_tax_id" flag

  • If "no_tax_id"= true, tax_id field should be empty, in case error return 422

  • If "no_tax_id"=false and age>14, tax_id should be present, in case error return 422

Check "patient_signed" flag

  • If "patient_signed" is not present in request, return 422 ("required property patient_signed was not present")

  • If "patient_signed"=true in request, return 422 ("value is not allowed in enum")

Validate person documents

  1. issued_at, issued_by is mandatory for documents

  2. Validate dates

    1. issued_at <= now() and issued_at => birth_date

      1.  in case `issued_at > now()` show error 422, "Document issued date should be in the past"

      2.  in case `issued_at < person.birth_date` show error 422, "Document issued date should greater than person.birth_date "

    2. expiration_date > now()

      1.  in case error show 422, "Document expiration_date should be in future"

      2. expiration_date is mandatory for document_type

        • NATIONAL_ID

        • COMPLEMENTARY_PROTECTION_CERTIFICATE

        • PERMANENT_RESIDENCE_PERMIT

        • REFUGEE_CERTIFICATE

        • TEMPORARY_CERTIFICATE

        • TEMPORARY_PASSPORT

      3. in case error return 422, "expiration_date is mandatory for document_type $.documents.type"

  3. Validate documents_type.number according to json schema 

    1. PASSPORT - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`

    2. NATIONAL_ID - `^[0-9]{9}$`

    3. BIRTH_CERTIFICATE - `^((?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]){2,25}$`

    4. COMPLEMENTARY_PROTECTION_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`

    5. REFUGEE_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`

    6. TEMPORARY_CERTIFICATE - `^(((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{4,6}|[0-9]{9}|((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{5}\\/[0-9]{5})$`

    7. TEMPORARY_PASSPORT - `^((?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]){2,25}$`

  4. if unzr exists and is not null, check pattern match "^[0-9]{8}-[0-9]{5}$"

    1. in case error return 422, msg 'string does not match pattern \"%{pattern}\"'

  5. if documents.type=NATIONAL_ID

    1. check if unzr exists in request, in case error return 422, msg "unzr is mandatory for document type NATIONAL_ID"

  6. Document numbersmaxLength < 25 

Search pending person requests

Search persons request  in IL_DB.person_requests to prevent requests duplication:

WHERE IL_DB.person_requests.data.person.tax_id = :($.person_requests.person.tax_id)
  AND IL_DB.person_requests.data.person.documents.number = :($.person_requests.person.documents.number)
  AND IL_DB.person_requests.status IN ('NEW', 'APPROVED')
  • if tax_id is null

WHERE IL_DB.person_requests.data.person.documents.number = :($.person_requests.person.documents.number)
  AND IL_DB.person_requests.data.person.first_name = :($.person_requests.person.first_name)
  AND IL_DB.person_requests.data.person.last_name = :($.person_requests.person.last_name)
  AND IL_DB.person_requests.status IN ('NEW', 'APPROVED')

Cancel person request

Change status of all found person requests:

SET   IL_DB.person_requests.status = 'CANCELED'
WHERE IL_DB.person_requests.id IN (:LIST)

Search pending declaration requests

Search declarations in IL_DB.declaration_requests to prevent requests duplication:

  • if tax_id is not null

WHERE IL_DB.declaration_requests.data.person.tax_id = :($.person_requests.person.tax_id)
  AND IL_DB.declaration_requests.status IN ('NEW', 'APPROVED')
  • if tax_id is null

WHERE IL_DB.declaration_requests.data.person.documents.number = :($.person_requests.person.documents.number)
  AND IL_DB.declaration_requests.status IN ('NEW', 'APPROVED')

If found declaration request - don't create person request. Return error "This person already has a declaration request"

Search person

We are looking for a person to prevent duplication of a person:

  • We create pairs of new person with people from clusters(tax_id, phone_number and number of the document) and send to the model.

    •  

      • in case deduplication model gave score <  PERSON_ONLINE_DEDUPLICATION_MATCH_SCORE, create new person

      • else return error 409, "such person exists. Update this person.

Validate phone number limit

USE_PHONE_NUMBER_AUTH_LIMIT is a flag in ehealth.charts that shows whether we count phones or not.

  • in case person is found, person_id will be saved to person_request, and person has the same authentication_methods.phone_number, we do not count phone numbers and do not compare the phone number with global_parameters.phone_number_auth_limit. So that we can update person, but still can not use phone over limit.

  • In case person is not found

    • Check if (SELECT count(*) from persons where authentication_methods::json->0->>'phone_number'='$.phone_number' and persons.status='active' and is_active=true)<global_parameters.phone_number_auth_limit
      in case error return 422, msg "This phone number is present more then $.global_parameters.phone_number_auth_limit times in the system"

Validate person authentication methods/phone

  1. If person <prm.global_parameters.no_self_auth_age years, then person.auth_methods.type = third_person. Validate that third_person has auth method.type = OTP

  2. if third_person.auth_method.type = OFFLINE - error `THIRD PERSON can't have OFFLINE self auth method type`

  3. if third_person.auth_method.type doesn't have active auth method - error `THIRD PERSON doesn't have active valid authentication methods`

  4. If third person >= prm.global_parameters.no_self_auth_age years

    1. in case error return 422, msg "Incorrect person age for such an action"

Person.auth_methods.type = third_persont.id. But on get Person request or Person display third_person.auth_method.phone_number.

  1. If person > prm.global_parameters.no_self_auth_age and he must have one of auth.method.type (OTP OR OFFLINE). Also person may use new endpoint Append auth methods to add additional auth_methods.type = third_person.

Don't validate auth_method.phone_number exists in verification.verified_phone.

Save person request

Insert record to IL.person_requests in status 'NEW'

Processing

Generate upload URL

Depending on the payload system generates list of signed urls for document scan-copies upload.

Signed URLs to be expired after some period of time (configurable `SECRETS_TTL`). If it has been expired - new person request should be created.

Each link is generated for one one-page document in .pdf, .jpg, .png, .bmp format. Document should be no more than 20 MB. For each type of documents, if couple of rules worked - only one single link is generated.

  1. Validate flag no_tax_id, if $.person_request.person.no_tax_id = true:

    1. Generate URL with type person.no_tax_id

  2. Validate if $.person_request.person.tax_id is not empty and $.person_request.person.no_tax_id = false then

    1. If (GetBirthDateFromTaxId($.tax_id) != $.birth_date) or (GetGenderFromTaxId($.tax_id) != $.gender) or CheckValidity($.tax_id) = false (i.e. invalid checksum) then

      • Generate URL with type person.tax_id

  3. Validate block confidant person. If person.confidant is not null:

    1. Generate URL's with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_relationship.[:].type}

    2. Generate URL's with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_person.[:].type}

  4. Validate block of person documents. If one of the documents has document.type = BIRTH_CERTIFICATE_FOREIGN and there is no same document in {$.person_request.person.confidant_person.[:].documents_relationship.[:]}

    and age < no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type BIRTH_CERTIFICATE_FOREIGN].type}

  5. Validate block of person documents. If one of the documents has document.type = PERMANENT_RESIDENCE_PERMIT and age >= no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type PERMANENT_RESIDENCE_PERMIT].type}

  6. Validate authentication_method. If authentication method = OFFLINE or third_person (and this third_person.auth_method = OFFLINE) - 

    1. Generate URL's with type person.{$.person_request.person.documents.[:].type} (or Generate URL's with type third_person.{$.third_person.documents.[:].type})

  7. Validate unzr. If $.person_request.person.unzr is not empty and first 8 digits of $.person_request.person.unzr != $.person_request.person.birth_date then

    1. Generate URL with type person.{$.person_request.person.unzr}

Invoke Media Content Storage to generate upload URL for each document obtained by executing logic above

IL.person_request.documents structure:

{
   "documents":[
      {
         "type":"person.no_tax_id",
         "url": "https://storage.googleapis.com/..."
      }
   ]
}

Save documents to DB.

Generate verification code

Invoke Initialize OTP to generate one time password and send it to client number. At this stage, the person receives an SMS message to confirm this phone and the consent to create a person.

Phone_number: ILperson_request.authentication_method_current.$.authentication_number

cURL example
curl -X POST \
  http://localhost:4000/verifications \
  -H 'content-type: application/json' \
  -d '{
  "phone_number": "+380936235985"
}'

Response structure examples

See on API-specification

 Response example (code: 201)
{
  "meta": {
    "code": 201,
    "url": "https://example.com/resource",
    "type": "object",
    "request_id": "6617aeec-15e2-4d6f-b9bd-53559c358f97#17810"
  },
  "data": {
    "status": "SIGNED",
    "id": "eeebb86d-5cba-43c9-885b-6482ecaf826b",
    "person": {
      "id": "13001c60-45a0-4b5a-b425-9505e1de18bd",
      "first_name": "Петро",
      "last_name": "Іванов",
      "second_name": "Миколайович",
      "birth_date": "2009-07-05",
      "birth_country": "Україна",
      "birth_settlement": "Вінниця",
      "gender": "MALE",
      "email": "email@example.com",
      "no_tax_id": false,
      "tax_id": "3999869394",
      "secret": "secret",
      "documents": [
        {
          "type": "BIRTH_CERTIFICATE",
          "number": "АА120518",
          "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
          "issued_at": "2017-02-28",
          "expiration_date": "2027-02-28"
        }
      ],
      "addresses": [
        {
          "type": "RESIDENCE",
          "country": "UA",
          "area": "Житомирська",
          "region": "Бердичівський",
          "settlement": "Київ",
          "settlement_type": "CITY",
          "settlement_id": "b075f148",
          "street_type": "STREET",
          "street": "вул. Ніжинська",
          "building": "15",
          "apartment": "23",
          "zip": "02090"
        }
      ],
      "phones": [
        {
          "type": "MOBILE",
          "number": "+380503410870"
        }
      ],
      "authentication_methods": [
        {
          "type": "THIRD_PERSON",
          "phone_number": "+380508887700",
          "value": "c282f8a9-e709-40aa-94b4-dde1402bf4b6",
          "alias": "husband"
        }
      ],
      "unzr": "20090705-00011",
      "emergency_contact": {
        "first_name": "Петро",
        "last_name": "Іванов",
        "second_name": "Миколайович",
        "phones": [
          {
            "type": "MOBILE",
            "number": "+380503410870"
          }
        ]
      },
      "confidant_person": [
        {
          "relation_type": "PRIMARY",
          "first_name": "Петро",
          "last_name": "Іванов",
          "second_name": "Миколайович",
          "birth_date": "1972-10-26",
          "birth_country": "Україна",
          "birth_settlement": "Вінниця",
          "gender": "MALE",
          "tax_id": "2659719350",
          "secret": "secret",
          "unzr": "19900101-00099",
          "preferred_way_communication": "email",
          "documents_person": [
            {
              "type": "PASSPORT",
              "number": "АА120518",
              "expiration_date": "2021-02-28",
              "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
              "issued_at": "2017-02-28"
            }
          ],
          "documents_relationship": [
            {
              "type": "BIRTH_CERTIFICATE",
              "number": "АА120518",
              "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
              "issued_at": "2017-02-28"
            }
          ],
          "phones": [
            {
              "type": "MOBILE",
              "number": "+380503410870"
            }
          ],
          "email": "emaill@example.com"
        }
      ],
      "preferred_way_communication": "email"
    },
    "patient_signed": false,
    "process_disclosure_data_consent": true,
    "channel": "MIS",
    "authorize_with": "cc949559-5dfe-420f-ac05-065e443b2cc6"
  },
  "urgent": {
    "authentication_method_current": [
      {
        "type": "OTP",
        "phone_number": "+38093*****85"
      }
    ],
    "documents": [
      {
        "type": "PASSPORT",
        "url": "https://storage.ehealth.world"
      }
    ]
  }
}
 Response example (code: 422)
{
  "meta": {
    "code": "422",
    "url": "https://example.com/resource",
    "type": "object",
    "request_id": "6617aeec-15e2-4d6f-b9bd-53559c358f97#17810"
  },
  "error": {
    "type": "unverified",
    "message": "Unverified phone number"
  }
}

Update person request

To update the data of an existing person use an endpoint `Create/Update person request`.

It is necessary to transfer the same json as when creating person, only to transfer the id of an existing person and do not transfer the block with the authentication methods.

If person.id is in request then 

  • validate person.id is UUID

    • in case error return 422

  • search person by person.id in MPI 

    • in case error return 422, "such person doesn't exist"

  • search persons in mpi (Пошук персон. Версія 3)

    • validate person be deduplication model (if score >  PERSON_ONLINE_DEDUPLICATION_UPDATE_SCORE, then add mpi_id to person request)

      • else return error 409, "Such person can't be updated. New person should be created instead" 

Update person’s data with empty value of the second name is possible by setting second_name = null.

Authorize

  1. Verify the validity of access token

  2. Check user scope person_request:write in order to perform this action

Request data validation

Validate request

Validate request using JSON schema

 JSON Schema
{
  "$schema": "http://json-schema.org/person_request/schema#",
  "definitions": {
    "phone": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: PHONE_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^\\+38[0-9]{10}$"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "name": {
      "type": "string",
      "pattern": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[a-zA-ZА-ЯҐЇІЄа-яґїіє0-9№\\\"!\\^\\*)\\]\\[(._-].*$"
    },
    "person_name": {
      "type": "string",
      "pattern": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\-]+(\\s(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\-]+)*$",
      "minLength": 1,
      "maxLength": 255
    },
    "unzr": {
      "type": "string",
      "pattern": "^[0-9]{8}-[0-9]{5}$"
    },
    "tax_id": {
      "type": "string",
      "pattern": "^[0-9]{10}$",
      "minLength": 10,
      "maxLength": 255
    },
    "no_tax_id": {
      "type": "boolean",
      "description": "Status person refused tax_id"
    },
    "gender": {
      "type": "string",
      "description": "Dictionary: GENDER",
      "maxLength": 255
    },
    "address": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: ADDRESS_TYPE"
        },
        "country": {
          "type": "string"
        },
        "area": {
          "$ref": "#/definitions/name"
        },
        "region": {
          "$ref": "#/definitions/name"
        },
        "settlement": {
          "$ref": "#/definitions/name"
        },
        "settlement_type": {
          "type": "string",
          "description": "settlement type Dictionary: SETTLEMENT_TYPE"
        },
        "settlement_id": {
          "type": "string",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
        },
        "street_type": {
          "type": "string",
          "description": "street type Dictionary: STREET_TYPE"
        },
        "street": {
          "$ref": "#/definitions/name"
        },
        "building": {
          "type": "string",
          "pattern": "^[1-9]((?![ЫЪЭЁыъэё])()([А-ЯҐЇІЄа-яґїіє \\/\\'\\-0-9])){0,20}$"
        },
        "apartment": {
          "type": "string"
        },
        "zip": {
          "type": "string",
          "pattern": "^[0-9]{5}$"
        },
        "inserted_by": {
          "type": "string"
        },
        "updated_by": {
          "type": "string"
        },
        "inserted_at": {
          "type": "string"
        },
        "updated_at": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "country",
        "area",
        "settlement",
        "settlement_type",
        "settlement_id",
        "inserted_by",
        "updated_by"
      ],
      "additionalProperties": false
    },
    "series_number_document": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "PASSPORT",
            "COMPLEMENTARY_PROTECTION_CERTIFICATE",
            "REFUGEE_CERTIFICATE",
            "TEMPORARY_CERTIFICATE"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$"
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "number_document": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "BIRTH_CERTIFICATE",
            "TEMPORARY_PASSPORT"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^(?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]+$",
          "minLength": 1,
          "maxLength": 255
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "id_card": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "NATIONAL_ID"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^[0-9]{9}$"
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "document_relationship": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: DOCUMENT_RELATIONSHIP_TYPE",
          "minLength": 1
        },
        "number": {
          "type": "string",
          "minLength": 1
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "person": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "first_name": {
          "type": "string"
        },
        "last_name": {
          "type": "string"
        },
        "second_name": {
          "type": "string"
        },
        "birth_date": {
          "type": "string"
        },
        "birth_country": {
          "type": "string"
        },
        "birth_settlement": {
          "type": "string"
        },
        "gender": {
          "enum": [
            "MALE",
            "FEMALE"
          ]
        },
        "email": {
          "type": "string"
        },
        "no_tax_id": {
          "type": "boolean"
        },
        "tax_id": {
          "type": "string"
        },
        "secret": {
          "type": "string"
        },
        "documents": {
          "type": "array"
        },
        "addresses": {
          "type": "array"
        },
        "phones": {
          "type": "array"
        },
        "unzr": {
          "type": "string"
        },
        "emergency_contact": {
          "type": "object",
          "properties": {
            "first_name": {
              "type": "string"
            },
            "last_name": {
              "type": "string"
            },
            "second_name": {
              "type": "string"
            },
            "phones": {
              "type": "array"
            }
          },
          "required": [
            "first_name",
            "last_name",
            "phones"
          ]
        },
        "confidant_person": {
          "type": "array"
        },
        "preferred_way_communication": {
          "enum": [
            "email",
            "phone"
          ]
        }
      },
      "required": [
        "first_name",
        "last_name",
        "birth_date",
        "birth_country",
        "birth_settlement",
        "gender",
        "no_tax_id",
        "tax_id",
        "secret",
        "documents",
        "addresses",
        "emergency_contact"
      ]
    },
    "patient_signed": {
      "type": "boolean"
    },
    "process_disclosure_data_consent": {
      "type": "boolean"
    }
  },
  "required": [
    "person",
    "patient_signed",
    "process_disclosure_data_consent"
  ]
}

Validate documents, confidant_person, flag no_tax_id

Validate documents, flag `no_tax_id`, confidant_person as on Create person request 

Validate authorize_with

The person can pass the id of his auth_method which he wants to confirm the update of the request. The necessary auth method can be found by making Get person's auth methods

  1. validate auth_method.id is UUID

    1. in case error return 422

  2. search auth method in MPI.person_authentication_method

    1. in case error return 422, "such authentication method doesn't exist"

  3. search auth method of this person where  MPI.person_authentication_method.person_id = $.person.id

    1. in case error return 422, "such authentication method does not belong to this person"

  4. validate that auth_method.type = NA

    1. in case error return 422, "Сannot be confirmed by a method with type= NA. Use a different method."

  5. validate that this method is active ( authentication_method.ended_at > now() and is_active = true)

This field is optional and set in il.person_reques.authentication_method_current.

If person request doesn't have this field, then choose that method which is returned from mpi as person's default method

Save person request

Insert record to IL.person_request in status 'NEW'. Person_id from request save in field mpi_id in IL.person_request

Search pending person requests

Search persons request  in IL_DB.person_requests to prevent requests duplication:

WHERE IL_DB.person_requests.data.person.id = :($.person_requests.person.id)
  AND IL_DB.person_requests.status IN ('NEW', 'APPROVED')

Cancel person requests

Change status of all found person requests:

SET   IL_DB.person_requests.status = 'CANCELED'
WHERE IL_DB.person_requests.id IN (:LIST)

Validate parameters

Person can't update tax_id. (He can update tax_id from null to tax_id or from null to null).

Also person can update birth_date if it validates with tax_id.

Validate auth_method_current

Set default auth method of person on IL.auth_method_request.auth_method_current - use function in mpi, that return default auth method

Validate that auth_method_current !=NA

Processing

Generate upload URL

Depending on the payload system generates list of signed urls for document scan-copies upload.

Signed URLs to be expired after some period of time (configurable `SECRETS_TTL`). If it has been expired - new person request should be created.

Each link is generated for one one-page document in jpeg format. Document should be no more than 10MB. For each type of documents only one single link is generated.

  1. Validate flag no_tax_id, if $.person_request.person.no_tax_id = true:

    1. Generate URL with type person.no_tax_id

  2. Validate if $.person_request.person.tax_id is not empty and $.person_request.person.no_tax_id = false then

    1. If (GetBirthDateFromTaxId($.tax_id) != $.birth_date) or (GetGenderFromTaxId($.tax_id) != $.gender) or CheckValidity($.tax_id) = false (i.e. invalid checksum) then

      • Generate URL with type person.tax_id

  3. Validate block confidant person. If person.confidant is not null:

    1. Generate URLs with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_relationship.[:].type}

    2. Generate URLs with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_person.[:].type}

  4. Validate block of person documents. If one of the documents has document.type = BIRTH_CERTIFICATE_FOREIGN and there is no same document in {$.person_request.person.confidant_person.[:].documents_relationship.[:]}

    and age < no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type BIRTH_CERTIFICATE_FOREIGN].type}

  5. Validate block of person documents. If one of the documents has document.type = PERMANENT_RESIDENCE_PERMIT and age >= no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type PERMANENT_RESIDENCE_PERMIT].type}

  6. Validate authentication_method. If authentication method = OFFLINE or third_person (and this third_person.auth_method = OFFLINE) - 

    1. Generate URLs with type person.{$.person_request.person.documents.[:].type} (or Generate URL's with type third_person.{$.third_person.documents.[:].type})

  7. Validate unzr. If $.person_request.person.unzr is not empty and first 8 digits of $.person_request.person.unzr != $.person_request.person.birth_date then

    1. Generate URL with type person.{$.person_request.person.unzr}

{
   "documents":[
      {
         "type":"person.no_tax_id",
         "url": "https://storage.googleapis.com/..."
      }
   ]
}

Save documents to DB.

Generate verification code

Invoke Initialize OTP to generate one time password and send it to client number. At this stage, the person receives an SMS message to confirm updating a person's data.

Phone_number: MPI.person_authentication_method where person_id = $person_request.persin_id and is_primary = True

cURL example
curl -X POST \
  http://localhost:4000/verifications \
  -H 'content-type: application/json' \
  -d '{
  "phone_number": "+380958697084"
}'

HTTP status codes

Response code

HTTP Status code

Message

Internal name

Description

1

Базові

2

201

Response

3

401

Invalid access token

4

401

Invalid legal entity type

5

403

Access denied. Party is not verified

6

403

Your scope does not allow to access this resource. Missing allowances: person_request:write

7

409

Invalid legal entity type

8

409

Such person can't be updated. Deduplication update score is lower than system value (less changes should be made)

9

409

Such person exists. Update this person

10

 

422

Confidant person is mandatory for children

 

11

422

Cannot be confirmed by a method with type= NA. Use a different method.

12

422

Document expiration_date should be in future

13

422

Document issued date should be in the past

14

422

Document issued date should greater than person.birth_date

15

422

Expiration_date is mandatory for document_type $.documents.type

16

422

Incorrect person age for such an action

17

422

Required property %{property} was not present

18

422

Required property patient_signed was not present

19

422

Schema does not allow additional properties

20

422

String does not match pattern ...

21

422

Such person doesn't exist

22

422

Such a phone already exists more N times

23

422

Such authentication method doesn't exist

24

422

Such authentication method does not belong to this person

25

422

This phone number is present more then $.global_parameters.phone_number_auth_limit times in the system

26

422

Unverified phone number

27

422

Unzr is mandatory for document type NATIONAL_ID

28

422

Unzr or birthdate are not correct

29

422

Value is not allowed in enum

30

Специфічні

31

 

422

Only for active MPI record can be created medication request!

 

 

Post-processing processes

Description of actions performed on data after processing

Technical modules where the method is used

List of pages describing technical modules where the method is used

 

  • No labels