
# (c) Secure Identity Alliance

openapi: 3.0.0
info:
  description: |
    The OSIA Enrollment Interface

    Change log:
    
    - 1.3.0:
      - Add structures to manage data encryption and integrity
      - Accept Verifiable Credential as supporting document
    - 1.2.1:
      - Add missing values in BiometricSubType
      - Use HTTP code 409 in case of conflict of ID in create operations
    - 1.2.0:
      - Remove array for enrollmentFlags and requestData
      - Change date to date-time
      - change mimetype to mimeType (upper case)
      - Add template, templateRef, templateFormat to biometricData
      - Add quality, qualityFormat, algorithm, vendor fields to biometricData
      - Mark some fields (ID, etc.) as readOnly
      - Add FORM in possible document type
    - 1.1.0:
      - Add error structure on 400 errors
      - Add additional documentType and open it for extension
      - Force additionalProperties to false when extension is not allowed
      - Rename operationId for create/read buffer
      - Add 404 error when missing
      - Add Digest header in create/read buffer
      - Support multiple content types for create/read buffer
      - Remove enrollmentId from the response of createEnrollment
      - Make the enrollment status optional in create & update operations
      - Add a contextualData entity to match what exists in population registry
      - Add pagination for findEnrollments
      - Add fields on BiometricData: instance, metadata, comment, missing
    - 1.0.0: Initial version

  version: 1.3.0
  title: OSIA Enrollment Interface
  license:
    name: SIA
    url: "https://raw.githubusercontent.com/SecureIdentityAlliance/osia/master/LICENSE"
tags:
  - name: Enrollment
  - name: Buffer
servers:
  - url: https://enrollment.com/
paths:

  /v1/enrollments/{enrollmentId}:
    post:
      tags:
        - Enrollment
      summary: Create one enrollment
      operationId: createEnrollment
      security:
        - BearerAuth: [enroll.write]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: finalize
          in: query
          description: Flag to indicate that data was collected (default is false).
          required: false
          schema:
            type: boolean
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Enrollment'
      responses:
        '204':
          description: Operation successful
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Operation not allowed
        '409':
          description: Creation not allowed, enrollmentId already exists
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      tags:
        - Enrollment
      summary: Read one enrollment
      operationId: readEnrollment
      security:
        - BearerAuth: [enroll.read]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
        - name: attributes
          in: query
          description: The (optional) set of required attributes to retrieve. If not present all attributes will be returned.
          required: false
          schema:
            type: array
            items:
              type: string
            example:
              - surname
              - familyname
      responses:
        '200':
          description: Read successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Enrollment'

        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Read not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      tags:
        - Enrollment
      summary: Update one enrollment
      operationId: updateEnrollment
      security:
        - BearerAuth: [enroll.write]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: finalize
          in: query
          description: Flag to indicate that data was collected (default is false).
          required: false
          schema:
            type: boolean
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Enrollment'
      responses:
        '204':
          description: Update successful
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Update not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    patch:
      tags:
        - Enrollment
      summary: Update partially one enrollment
      description: Update partially an enrollment. Payload content is a partial enrollment object compliant with RFC7396.
      operationId: partialUpdateEnrollment
      security:
        - BearerAuth: [enroll.write]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: finalize
          in: query
          description: Flag to indicate that data was collected (default is false).
          required: false
          schema:
            type: boolean
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Enrollment'
            examples:
              Example of updating only 2 biographicData elements:
                value:
                  biographicData:
                    gender: null
                    nationality: FRA
              Example of updating the list of documents with one VerifiableCredential:
                value:
                  documentData:
                  - documentType: ID_CARD
                    parts:
                    - data: "VC DATA"
                      mimeType: application/vc
      responses:
        '204':
          description: Update successful
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Update not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

    delete:
      tags:
        - Enrollment
      summary: Delete one enrollment
      operationId: deleteEnrollment
      security:
        - BearerAuth: [enroll.write]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Delete successful
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Operation not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
                

  /v1/enrollments/{enrollmentId}/finalize:
    put:
      tags:
        - Enrollment
      summary: Finalize one enrollment
      operationId: finalizeEnrollment
      security:
        - BearerAuth: [enroll.write]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Update successful
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Update not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
                
  /v1/enrollments:
    post:
      tags:
        - Enrollment
      summary: Retrieve a list of enrollments which match passed in search criteria
      operationId: findEnrollments
      security:
        - BearerAuth: [enroll.read]
      parameters:
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
        - name: offset
          in: query
          description: The offset of the query (first item of the response)
          required: false
          schema:
            type: integer
            default: 0
        - name: limit
          in: query
          description: The maximum number of items to return
          required: false
          schema:
            type: integer
            default: 100
      requestBody:
        description: A set of expressions on attributes of the person
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Expressions'
            example:
              - attributeName: firstName
                operator: "="
                value: John
              - attributeName: dateOfBirth
                operator: "<"
                value: "1990-12-31"
      responses:
        '200':
          description: Query successful
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Enrollment'

        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Query not allowed
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
                
  /v1/enrollments/{enrollmentId}/buffer:
    post:
      tags:
        - Buffer
      summary: Create a buffer
      description: This service is used to send separately the buffers of the images
      operationId: createBuffer
      security:
        - BearerAuth: [enroll.buf.write]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
        - name: Digest
          in: header
          description: the buffer digest, as defined per RFC 3230.
          schema:
            type: string
          example: "SHA=thvDyvhfIqlvFe+A9MYgxAfm1q5="
          required: false
      requestBody:
        description: The image of the request
        required: true
        content:
          application/*:
            schema:
              type: string
              format: binary
              example: ABCDEFG...
          image/*:
            schema:
              type: string
              format: binary
              example: ABCDEFG...
      responses:
        '201':
          description: Operation successful
          content:
            application/json:
              schema:
                type: object
                required:
                  - bufferId
                properties:
                  bufferId:
                    type: string
                additionalProperties: false
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Operation not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
            
  /v1/enrollments/{enrollmentId}/buffer/{bufferId}:
    get:
      tags:
        - Buffer
      summary: Read a buffer
      description: |
        This service is used to get the buffer of the images.
        The content type of the response is the content type used when the buffer was created.
      operationId: readBuffer
      security:
        - BearerAuth: [enroll.buf.read]
      parameters:
        - name: enrollmentId
          in: path
          description: the id of the enrollment
          required: true
          schema:
            type: string
        - name: bufferId
          in: path
          description: the id of the buffer
          required: true
          schema:
            type: string
        - name: transactionId
          in: query
          description: The id of the transaction
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Read successful
          headers:
            Digest:
              description: the buffer digest, as defined per RFC 3230.
              schema:
                type: string
              example: "SHA=thvDyvhfIqlvFe+A9MYgxAfm1q5="
              required: false
          content:
            application/*:
              schema:
                description: The image
                type: string
                format: binary
                example: ABCDEFG...
            image/*:
              schema:
                description: The image
                type: string
                format: binary
                example: ABCDEFG...
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Update not allowed
        '404':
          description: Unknown record
        '500':
          description: Unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          description: Error code
          type: integer
          format: int32
        message:
          description: Error message
          type: string
      additionalProperties: false
    Encryption:
      type: object
      description: if present, indicates that a part of the data is encrypted using the provided format.
      required:
        - type
        - scope
      properties:
        type:
          type: string
          enum: [JWE, PKCS7]
        scope:
          description: |
            A whitespace-separated list of JSON paths to nodes containing encrypted data.
            For each node:

            - If the node is a JSON object, the full content is encrypted and the node transformed to a single buffer.
              Canonicalization is recommended before encryption but not mandatory.
            - If the node is an embedded buffer (image, PDF, etc.), the value is replaced with the encrypted data.
            - If the node is a URL to a buffer, the node remains a URL in clear format but the
              pointed buffer is encrypted.
          type: string
      additionalProperties: false
    Integrity:
      description: |
        Object describing the integrity (hash and signature) of a sub set of data.

        It is possible to calculate multiple integrity blocks corresponding to different
        use cases: integrity before encryption, integrity limited to a small sub set of data and easy
        to check, etc.
      type: object
      required:
        - scope
        - alg
        - hash
      properties:
        id:
          type: string
          description: An optional ID used in JSONPath expression to select a single integrity object
        type:
          type: string
          description: |
            Format of the signature of the hash.

            Cryptographic signature is optional. Use NONE when only the hash is required.
          enum: [NONE, JWS, PKCS7]
          default: NONE
        scope:
          description: |
            A whitespace-separated list of JSON paths to nodes containing the data to include in the
            hash calculation.

            It is used to build a JSON limited to the nodes identified in this scope. Then this
            JSON is canonicalized and a hash is calculated.
          type: string
        alg:
          description: |
            Hash algorithm used to calculate the hash.
            Example of possible values: SHA256, SHA384, SHA512.
          type: string
        encrypted:
          description: if true, indicates that the hash was calculated using encrypted data.
          type: boolean
          default: false
        followRef:
          description: |
            if true, indicates that the referenced buffers must be fetched and included in the hash.
            If false, only the URL is considered for the hash calculation
          type: boolean
          default: false
        hash:
          description: |
            Hash calculated from the attributes listed in scope. Hash is calculated using the following process:

            - Build an intermediate JSON containing only the fields identified in the scope
            - Canonicalize the JSON using RFC8785
            - Hash the result
            - If 'followRef' is true, include in the hash computation the binary data referenced
              by URI included in the scope.
          type: string
        signature:
          description: |
            the signature of the hash.
            Compact format is used for JWS and PEM format for PKCS7.
          type: string
        signatureRef:
          type: string
          format: uri
          description: URI to the signature data. DER format is accepted for PKCS7 to optimize the storage space.
          example: "https://objectserver.com/signature?id=00003"
      additionalProperties: false
    Enrollment:
      type: object
      required:
        - enrollmentId
        - status
      properties:
        enrollmentId:
          type: string
          readOnly: true
        status:
          type: string
          enum: [FINALIZED, IN_PROGRESS]
          readOnly: true
        enrollmentType:
          type: string
          description: "Type of the enrollment (example: citizen, resident, etc.)"
        enrollmentFlags:
          $ref: '#/components/schemas/EnrollmentFlags'
        requestData:
          $ref: '#/components/schemas/RequestData'
        contextualData:
          $ref: '#/components/schemas/ContextualData'
        biographicData:
          $ref: '#/components/schemas/BiographicData'
        biometricData:
          type: array
          items:
            $ref: '#/components/schemas/BiometricData'
        documentData:
          type: array
          items:
            $ref: '#/components/schemas/DocumentData'
        encryption:
          $ref: '#/components/schemas/Encryption'
        integrity:
          type: array
          items:
            $ref: '#/components/schemas/Integrity'
      additionalProperties: false
    RequestData:
      description: The data describing the request associated to the enrollment (i.e. why the enrollment is done). Can be extended.
      example:
        priority: 1
        requestType: "FIRST_ISSUANCE"
        deliveryAddress:
          address1: 11 Rue des Rosiers
          city: Libourne
          postalCode: "33500"
          country: France
    EnrollmentFlags:
      description: The enrollment custom flags (i.e. the properties of the enrollment process). Can be extended.
      example:
        timeout: 3600
        other: "other"
    ContextualData:
      description: The set of contextual data.
      example:
        enrollmentDate: "2019-01-11"
    BiographicData:
      description: The set of biographic data.
      example:
        firstName: John
        lastName: Doo
        dateOfBirth: "1985-11-30"
        gender: M
        nationality: FRA
    BiometricData:
      type: object
      required:
        - biometricType
      properties:
        biometricType:
          $ref: '#/components/schemas/BiometricType'
        biometricSubType:
          $ref: '#/components/schemas/BiometricSubType'
        instance:
          type: string
          description: Used to separate two distincts biometric items of the same type and subtype
        image:
          type: string
          description: Encoded image buffer
        imageRef:
          type: string
          format: uri
          description: URI to an image
          example: "http://imageserver.com/image?id=00003"
        captureDate:
          description: Data & time of the data capture, using RFC3339 format
          type: string
          format: date-time
          example: "2019-05-21T12:00:00+01:00"
        captureDevice:
          type: string
          description: A string identifying the device used to capture the biometric
        impressionType:
          $ref: '#/components/schemas/ImpressionType'
        width:
          type: integer
          description: the width of the image
        height:
          type: integer
          description: the height of the image
        bitdepth:
          type: integer
        mimeType:
          type: string
          description: the nature and format of the image. The mime type definitions should be in compliance with RFC 6838.
        resolution:
          type: integer
          description: the image resolution (in DPI)
        compression:
          $ref: '#/components/schemas/CompressionType'
        missing:
          description: Optional properties indicating if a part of the biometric data is missing
          type: array
          items:
            $ref: '#/components/schemas/MissingType'
        metadata:
          type: string
          description: An optional string used to convey information vendor-specific
        comment:
          type: string
          description: A comment about the biometric data
        template:
          type: string
          description: Encoded template buffer
        templateRef:
          type: string
          format: uri
          description: URI to the template when it is managed in a dedicated data server
          example: "http://dataserver.com/template?id=00014"
        templateFormat:
          $ref: '#/components/schemas/TemplateFormat'
        quality:
          type: integer
          format: int64
          description: Quality, as a number, of the biometric
        qualityFormat:
          $ref: '#/components/schemas/QualityFormat'
        algorithm:
          type: string
        vendor:
          type: string
        encryption:
          $ref: '#/components/schemas/Encryption'
        integrity:
          type: array
          items:
            $ref: '#/components/schemas/Integrity'
      additionalProperties: false
    TemplateFormat:
      type: string
      description: |
        Format of the template.
        One of ISO_19794_2, ISO_19794_2_NS, ISO_19794_2_CS, ISO_19794_2_2011, ANSI_378_2009 or ANSI_378.
        Can be extended to include additional proprietary template format
    QualityFormat:
      type: string
      description: |
        Format of the quality.
        One of ISO_19794, NFIQ, or NFIQ2.
        Can be extended to include additional proprietary quality format
    MissingType:
      type: object
      properties:
        biometricSubType:
          $ref: '#/components/schemas/BiometricSubType'
        presence:
          type: string
          enum: [BANDAGED, AMPUTATED, DAMAGED]
      additionalProperties: false
    DocumentPart:
      type: object
      properties:
        pages:
          type: array
          description: The pages included in this part. Can be a single page number, or a list.
          minItems: 1
          items:
            type: integer
        data:
          type: string
          description: Encoded data buffer
        dataRef:
          type: string
          format: uri
          description: URI to the data
          example: "http://server.com/buffer?id=00003"
        width:
          type: integer
          description: the width of the image in pixels
        height:
          type: integer
          description: the height of the image in pixels
        mimeType:
          type: string
          description: |
            the nature and format of the document.
            The mime type definitions should be in compliance with RFC 6838.
            Verifiable Credentials can be used if the proper mimeType is used.
        captureDate:
          description: Data & time of the data capture, using RFC3339 format
          type: string
          format: date-time
          example: "2019-05-21T12:00:00+01:00"
        captureDevice:
          type: string
          description: A string identifying the device used to capture the document part
        encryption:
          $ref: '#/components/schemas/Encryption'
        integrity:
          type: array
          items:
            $ref: '#/components/schemas/Integrity'
      additionalProperties: false
    DocumentData:
      type: object
      required:
        - documentType
        - parts
      properties:
        documentType:
          $ref: '#/components/schemas/DocumentType'
        documentTypeOther:
          type: string
          description: Details about the type of document when OTHER is used.
        instance:
          type: string
          description: "Used to separate two distincts documents of the same type (ex: two passports)"
        parts:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/DocumentPart'
        integrity:
          type: array
          items:
            $ref: '#/components/schemas/Integrity'
      additionalProperties: false
    DocumentType:
      type: string
      description: Type of document.
      enum: [ID_CARD, PASSPORT, INVOICE, BIRTH_CERTIFICATE, FORM, OTHER]
      example: FORM
    Expression:
      type: object
      required:
        - attributeName
        - operator
        - value
      properties:
        attributeName:
          type: string
        operator:
          type: string
          enum: ['<', '>', '=', '>=', '<=', '!=']
        value:
          oneOf:
          - type: string
          - type: integer
          - type: number
          - type: boolean
      additionalProperties: false
    Expressions:
      type: array
      items:
        $ref: '#/components/schemas/Expression'
    CompressionType:
      type: string
      enum: [NONE, WSQ, JPEG, JPEG2000, PNG]
      example: WSQ
    ImpressionType:
      type: string
      enum:
        - LIVE_SCAN_PLAIN
        - LIVE_SCAN_ROLLED
        - NONLIVE_SCAN_PLAIN
        - NONLIVE_SCAN_ROLLED
        - LATENT_IMPRESSION
        - LATENT_TRACING
        - LATENT_PHOTO
        - LATENT_LIFT
        - LIVE_SCAN_SWIPE
        - LIVE_SCAN_VERTICAL_ROLL
        - LIVE_SCAN_PALM
        - NONLIVE_SCAN_PALM
        - LATENT_PALM_IMPRESSION
        - LATENT_PALM_TRACING
        - LATENT_PALM_PHOTO
        - LATENT_PALM_LIFT
        - LIVE_SCAN_OPTICAL_CONTACTLESS_PLAIN
        - OTHER
        - UNKNOWN
    BiometricType:
      type: string
      enum:
        - FACE
        - FINGER
        - IRIS
        - SIGNATURE
        - UNKNOWN
      example: FINGER
    BiometricSubType:
      type: string
      enum:
        - UNKNOWN
        - RIGHT_THUMB
        - RIGHT_INDEX
        - RIGHT_MIDDLE
        - RIGHT_RING
        - RIGHT_LITTLE
        - LEFT_THUMB
        - LEFT_INDEX
        - LEFT_MIDDLE
        - LEFT_RING
        - LEFT_LITTLE
        - PLAIN_RIGHT_FOUR_FINGERS
        - PLAIN_LEFT_FOUR_FINGERS
        - PLAIN_THUMBS
        
        - UNKNOWN_PALM
        - RIGHT_FULL_PALM
        - RIGHT_WRITERS_PALM
        - LEFT_FULL_PALM
        - LEFT_WRITERS_PALM
        - RIGHT_LOWER_PALM
        - RIGHT_UPPER_PALM
        - LEFT_LOWER_PALM
        - LEFT_UPPER_PALM
        - RIGHT_OTHER
        - LEFT_OTHER
        - RIGHT_INTERDIGITAL
        - RIGHT_THENAR
        - RIGHT_HYPOTHENAR
        - LEFT_INTERDIGITAL
        - LEFT_THENAR
        - LEFT_HYPOTHENAR
        
        - RIGHT_INDEX_AND_MIDDLE
        - RIGHT_MIDDLE_AND_RING
        - RIGHT_RING_AND_LITTLE
        - LEFT_INDEX_AND_MIDDLE
        - LEFT_MIDDLE_AND_RING
        - LEFT_RING_AND_LITTLE
        - RIGHT_INDEX_AND_LEFT_INDEX
        - RIGHT_INDEX_AND_MIDDLE_AND_RING
        - RIGHT_MIDDLE_AND_RING_AND_LITTLE
        - LEFT_INDEX_AND_MIDDLE_AND_RING
        - LEFT_MIDDLE_AND_RING_AND_LITTLE
        
        - EYE_UNDEF
        - EYE_RIGHT
        - EYE_LEFT
        - EYE_BOTH
        
        - PORTRAIT
        - LEFT_PROFILE
        - RIGHT_PROFILE
      example: RIGHT_INDEX

