openapi: 3.1.1

info:
  title: Mobile Identity API
  description: Mobile Identity API
  version: 1.0.0

servers:
  - url: 'https://api.cm.com/mobile-identity/v1'
  - url: 'https://api.cm.com/mobile-identity-sandbox/v1'

security: [ { JWT: [ ] } ]

tags:
  - name: Identity Match
    description: Request an Identity Match check
  - name: SIM Swap
    description: Request a SIM Swap check
  - name: Number Verify
    description: Verify a phone number
  - name: Callbacks
    description: Updates sent to the `callbackUrl` provided when requesting a number verify

paths:
  /sim-swap:
    post:
      operationId: create_sim_swap
      summary: SIM swap
      description: Request the date time of the last SIM swap of the provided phone number
      tags: [ SIM Swap ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimSwapRequest'
      responses:
        '200':
          description: Retrieved SIM Swap information. Response depends on the provided service type request field.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SimSwapTimestampResponse'
                  - $ref: '#/components/schemas/SimSwap24hResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /identity-match:
    post:
      operationId: create_identity_match
      summary: Identity Match
      description: Match the provided person details to the given phone number
      tags: [ Identity Match ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IdentityMatchRequest'
      responses:
        '200':
          description: Boolean or score out of 100 per property regarding its match. Response depends on the provided service type request field.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/IdentityMatchMatchResponse'
                  - $ref: '#/components/schemas/IdentityMatchScoreResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /number-verify:
    post:
      operationId: create_number_verify
      summary: Request number verify
      description: Verify if a provided phone number is valid and online
      tags: [ Number Verify ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NumberVerifyRequest'
      responses:
        '200':
          description: Phone number verification has been requested
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/NumberVerifyResponse'
                  - type: object
                    properties:
                      sessionUrl:
                        type: [ 'string', 'null' ]
                        description: The URL loaded from the mobile device connected to the mobile network
                        examples: [ 'http://example.com/v1/dm/session/d635424bb0a54d388477cb17fa308655' ]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /number-verify/{transactionId}:
    parameters:
      - $ref: '#/components/parameters/TransactionId'
    get:
      operationId: get_number_verify
      summary: Retrieve number verify
      description: Retrieve a single number verify transaction and its information
      tags: [ Number Verify ]
      responses:
        '200':
          description: Phone number verification has been retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NumberVerifyResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

webhooks:
  numberVerifyState:
    post:
      operationId: callback_number_verify_state
      summary: Number verify state
      description: |
        Sent to the `callbackUrl` provided when [requesting the number verify](#tag/Number-Verify/operation/create_number_verify), every time the state of the number verify transaction changes. Use it as a trigger to retrieve the latest details with the [Retrieve number verify](#tag/Number-Verify/operation/get_number_verify) endpoint.

        The request is signed so you can verify its authenticity and integrity. The signature is calculated using HMAC-SHA256, with the request body as the message and the client secret as the secret key, and is sent in the `Authorization` header. Repeat this calculation on the received body and compare the result with the header value.

        Respond with a status code in the 2xx range; the response body is ignored. When your endpoint responds with a 5xx status code, the callback is retried several times.
      tags: [ Callbacks ]
      security: [ { HMAC: [ ] } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NumberVerifyStateEvent'
            examples:
              completed:
                $ref: '#/components/examples/number-verify-state-event'
      responses:
        '2XX':
          description: Callback received. Any status code in the 2xx range is accepted, the response body is ignored.

components:
  schemas:
    SimSwapRequest:
      type: object
      properties:
        phoneNumber:
          type: string
          description: The phone number to match the person to. Must be in E.164 format.
          examples: [ '+31612345678' ]
        serviceType:
          $ref: '#/components/schemas/SimSwapType'
          description: Type of SIM Swap response to be retrieved.
          examples: [ '24h' ]
      required: [ phoneNumber, serviceType ]

    SimSwapTimestampResponse:
      type: object
      properties:
        state:
          $ref: '#/components/schemas/ResponseState'
        timestamp:
          type: string
          description: Last SIM Swap for that phone number in ISO 8601 format
          format: date-time
          examples: [ '2026-01-01T00:00:00Z' ]

    SimSwap24hResponse:
      type: object
      properties:
        state:
          $ref: '#/components/schemas/ResponseState'
        24h:
          type: boolean
          description: Boolean if the phone number has been SIM swapped in the last 24 hours
          examples: [ false ]

    IdentityMatchRequest:
      type: object
      properties:
        phoneNumber:
          type: string
          description: The phone number to match the person to. Must be in E.164 format.
          examples: [ '+31612345678' ]
        serviceType:
          $ref: '#/components/schemas/IdentityMatchType'
          description: Type of Identity Match response to be retrieved.
          examples: [ 'match' ]
        firstName:
          type: [ 'string', 'null' ]
          description: The first name of the person to match to
          maxLength: 255
          examples: [ 'John' ]
        lastName:
          type: [ 'string', 'null' ]
          description: The last name of the person to match to
          maxLength: 255
          examples: [ 'Doe' ]
        address:
          type: [ 'string', 'null' ]
          description: House number, first line of the address of the person to match to
          maxLength: 255
          examples: [ 'Konijnenberg 24' ]
        address2:
          type: [ 'string', 'null' ]
          description: Optional additional address line
          maxLength: 255
        address3:
          type: [ 'string', 'null' ]
          description: Optional additional address line
          maxLength: 255
        postalCode:
          type: [ 'string', 'null' ]
          description: Postal code of the address of the person to match to
          maxLength: 255
          examples: [ '4825 BD' ]
        dateOfBirth:
          type: [ 'string', 'null' ]
          description: The date of birth of the person to match to. In 'YYYY-MM-DD' format.
          format: date
          examples: [ '1965-03-10' ]
      required: [ phoneNumber, serviceType ]

    IdentityMatchMatchResponse:
      type: object
      properties:
        state:
          $ref: '#/components/schemas/ResponseState'
        firstNameMatch:
          type: [ 'boolean', 'null' ]
          description: If the provided first name matched to the provided phone number. The value can be `null` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          examples: [ true ]
        lastNameMatch:
          type: [ 'boolean', 'null' ]
          description: If the provided last name matched to the provided phone number. The value can be `null` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          examples: [ true ]
        nameMatch:
          type: [ 'boolean', 'null' ]
          description: If the provided full name matched to the provided phone number. The value can be `null` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          examples: [ true ]
        addressMatch:
          type: [ 'boolean', 'null' ]
          description: If the provided address matched to the provided phone number. The value can be `null` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          examples: [ true ]
        postalCodeMatch:
          type: [ 'boolean', 'null' ]
          description: If the provided postal code matched to the provided phone number. The value can be `null` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          examples: [ true ]
        dateOfBirthMatch:
          type: [ 'boolean', 'null' ]
          description: If the provided date of birth matched to the provided phone number. The value can be `null` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          examples: [ true ]

    IdentityMatchScoreResponse:
      type: object
      properties:
        state:
          $ref: '#/components/schemas/ResponseState'
        firstNameScore:
          type: integer
          description: Score of the match of the provided first name to the provided phone number. The value can be `-1` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          minimum: -1
          maximum: 100
          examples: [ 100 ]
        lastNameScore:
          type: integer
          description: Score of the match of the provided last name to the provided phone number. The value can be `-1` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          minimum: -1
          maximum: 100
          examples: [ 100 ]
        nameScore:
          type: integer
          description: Score of the match of the provided full name to the provided phone number. The value can be `-1` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          minimum: -1
          maximum: 100
          examples: [ 100 ]
        addressScore:
          type: integer
          description: Score of the match of the provided address to the provided phone number. The value can be `-1` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          minimum: -1
          maximum: 100
          examples: [ 100 ]
        postalCodeScore:
          type: integer
          description: Score of the match of the provided postal code to the provided phone number. The value can be `-1` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          minimum: -1
          maximum: 100
          examples: [ 100 ]
        dateOfBirthScore:
          type: integer
          description: Score of the match of the provided date of birth to the provided phone number. The value can be `-1` if the data is not available or accessible, or if an unexpected error is returned when retrieving the data from the operator.
          minimum: -1
          maximum: 100
          examples: [ 100 ]

    NumberVerifyRequest:
      type: object
      properties:
        phoneNumber:
          type: string
          description: The phone number to verify. Must be in E.164 format.
          examples: [ '+31612345678' ]
        callbackUrl:
          type: string
          description: Updates regarding the number verify transaction will be sent to the callback URL. It must begin with `https://`. See the [Number verify state](#tag/Callbacks/operation/callback_number_verify_state) callback for the payload that is sent.
          format: url
          examples: [ 'https://example.com' ]
      required: [ phoneNumber, callbackUrl ]

    NumberVerifyResponse:
      type: object
      properties:
        id:
          type: string
          description: ID of the number verify transaction
          format: uuid
          examples: [ '6f8d0a9d-b85c-4c3f-9e69-5699f1e00f49' ]
        state:
          $ref: '#/components/schemas/State'
          description: State of the number verify transaction
          examples: [ 'completed' ]
        match:
          type: [ 'boolean', 'null' ]
          description: Is the number verified. If state is pending, match is null.
          examples: [ true ]

    NumberVerifyStateEvent:
      title: Number Verify State Event
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the event.
          examples: [ '58128784-9e8d-4424-a89d-08bfe273381c' ]
        type:
          $ref: '#/components/schemas/EventType'
        created:
          type: string
          format: date-time
          description: The time the event was created, in ISO 8601 format.
          examples: [ '2026-01-01T00:00:00+00:00' ]
        numberVerify:
          type: object
          properties:
            id:
              type: string
              format: uuid
              description: ID of the number verify transaction
              examples: [ '6f8d0a9d-b85c-4c3f-9e69-5699f1e00f49' ]
            state:
              $ref: '#/components/schemas/State'
              description: State of the number verify transaction
              examples: [ 'completed' ]
            match:
              type: [ 'boolean', 'null' ]
              description: Is the number verified. If state is pending, match is null.
              examples: [ true ]
          required: [ id, state, match ]
      required: [ id, type, created, numberVerify ]

    EventType:
      type: string
      description: >
        Supported event types:

         * `numberVerify.state` - The number verify transaction has been updated.

      enum: [ numberVerify.state ]
      examples: [ numberVerify.state ]

    ErrorResponse:
      title: Error Response
      type: object
      properties:
        status:
          type: integer
          format: int32
          description: Response status code, should match HTTP error code.
          examples: [ 400 ]
        message:
          type: string
          description: Description of the error that occurred.
          examples: [ 'The phone number field is required' ]
        code:
          $ref: '#/components/schemas/ErrorCode'

    SimSwapType:
      type: string
      enum: [ timestamp, 24h ]

    IdentityMatchType:
      type: string
      enum: [ match, score ]

    State:
      type: string
      enum: [ pending, completed, unavailable ]

    ResponseState:
      type: string
      description: State that indicates whether the request was successful or the data could not be retrieved due to unavailability.
      enum: [ success, unavailable ]

    ErrorCode:
      type: integer
      description: >
        Error code description:

         * 1000 - Unknown error
         * 1001 - Invalid request
         * 1002 - Supplier error
         * 1003 - Unsupported configuration
         * 2000 - Validation error
         * 2001 - Invalid `phoneNumber` field
         * 2002 - Invalid `serviceType` field
         * 2003 - Invalid `firstName` field
         * 2004 - Invalid `lastName` field
         * 2005 - Invalid `address` field
         * 2006 - Invalid `postalCode` field
         * 2007 - Invalid `dateOfBirth` field
         * 2008 - Invalid `callbackUrl` field
         * 3000 - Feature not enabled
         * 3001 - Phone number is not active

      enum: [ 1000, 1001, 1002, 1003, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 3000, 3001 ]
      examples: [ 2001 ]

  examples:
    number-verify-state-event:
      summary: Number verify completed
      value:
        id: '58128784-9e8d-4424-a89d-08bfe273381c'
        type: 'numberVerify.state'
        created: '2026-01-01T00:00:00+00:00'
        numberVerify:
          id: '6f8d0a9d-b85c-4c3f-9e69-5699f1e00f49'
          state: 'completed'
          match: true

  responses:
    BadRequest:
      description: Errors related to the request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 400
            message: The phone number field is required
            code: 2001

    Unauthorized:
      description: Errors related to the authorization.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 401
            message: Unauthorized
            code: 1000

    NotFound:
      description: Errors related to the request URL
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 404
            message: Not found
            code: 1000

    InternalServerError:
      description: Errors related to the transaction.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 500
            message: Transaction could not be started
            code: 1002

  parameters:
    TransactionId:
      name: transactionId
      in: path
      schema:
        type: string
        format: uuid
      required: true
      description: A unique identifier for the transaction.
      example: '6f8d0a9d-b85c-4c3f-9e69-5699f1e00f49'

  securitySchemes:
    JWT:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        In order to authenticate you need to use your credentials to generate a JWT Bearer token. The [JWT token](https://jwt.io/introduction/) has to be generated using the `HS256` algorithm and your credentials. This JWT has to contain the following attributes: `iat`, `nbf`, `exp`  in the payload, as well as the attribute `kid` in the header of the JWT. This `kid` attribute needs to contain the Key Id of your credentials.

        The generated token needs to be passed via the HTTP Authorization header like:

        ```
        Authorization: Bearer GENERATED_TOKEN_HERE
        ```

        There are many libraries available for different programming languages that can help you to generate a JWT. See the Libraries tab on [https://jwt.io](https://jwt.io)

    HMAC:
      type: apiKey
      in: header
      name: Authorization
      description: |
        Used on callbacks sent by Mobile Identity to your `callbackUrl`. The header contains the HMAC-SHA256 signature of the request body, calculated with your client secret as the secret key, prefixed with `HMAC `:

        ```
        Authorization: HMAC MIi9ZMyar2v+o7H7LD7oNolO5LrTJaC+8uKvYUGqJvM=
        ```
