Registering a Pay user

In order to create a Pay user on your environment, multiple things need to happen. Since Vipaso uses a separate identity provider service, the user needs to be created there. The service works with so called flows, so the first thing is to create one. Then you need to gather information from your user, for example name, phone number and passcode. Additionally, before you could decorate the flow with the gathered user information, you need to verify the phone number, we use OTP verification for this. Once all information is gathered and verified, you can finalize the flow.

1. Starting the flow and sending the OTP code

The SDK aims to shorten the number of steps so its first call already accepts a phone number that it will send the OTP verification code to.

let request = StartSignupRequest(phoneNumber: phoneNumber)
vipasoPay.startSignupFlow(request: request) { result in
    switch result {
    case .success(let response):
        // Success: you need to use response.flowID in the next call
    case .failure(let error):
        switch error {
        case .signup(.otp(let otpError)):
            // Error: the OTP code could not be delivered
        default:
            // Error: any other error, server or network errors
        }
    }
}
val request = StartSignupRequest(phoneNumber)
return vipasoPay.startSignupFlow(request) // Success returns flowId

If you debug your networking calls, you should see the following traffic:

  1. HTTP request and response for retrieving the flow id in the background:
GET /a/self-service/registration/api HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
  "id": "ef23c1db-0000-4022-873c-cf26fc1372fa",
  ...
}
  1. HTTP request and response for sending the OTP code in the background:
POST /identity/verification/flow/phone HTTP/1.1
Content-Type: application/json
{
  "phoneNumber": "+439999999999",
  "phoneType": "PRIMARY",
  "flowId": "ef23c1db-0000-4022-873c-cf26fc1372fa",
  "flowType": "REGISTRATION"
}
HTTP/1.1 201 Created

Example screenshots from our development application:

2. Verifying the OTP code

Once the OTP arrived, you need to verify it in our system. You will also need to forward the flow identifier that your first response returned.

let request = VerifyPhoneNumberRequest(flowID: flowID, otp: otp)
vipasoPay.verifyPhoneNumber(request: request) { result in
    switch result {
    case .success(let response):
        // Success: returns the same flowID
    case .failure(let error):
        // Error: any server or network error
    }
}
val request = VerifyPhoneNumberRequest(flowId, otp)
return vipasoPay.verifyPhoneNumber(request) // Success returns flowId

HTTP request and response happening in the background:

PATCH /identity/verification/flow/phone HTTP/1.1
Content-Type: application/json
{
  "phoneType": "PRIMARY",
  "flowId": "ef23c1db-0000-4022-873c-cf26fc1372fa",
  "otp": "271501",
  "flowType": "REGISTRATION"
}

Actual HTTP response in the background:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
  "message": "Phone verified successfully"
}

Example screenshots from our development application:

3. Decorating the flow with user information and finalizing registration

Once the phone number is verified, you can send the gathered user information and finalize the flow.

let request = FinishSignupRequest(
    flowID: flowID,
    password: password,
    email: email,
    firstName: firstName,
    lastName: lastName,
    phoneNumber: phoneNumber
)
vipasoPay.finishSignupFlow(request: request) { result in
    switch result {
    case .success(let response):
        // Success: returns the same flowID
    case .failure(let error):
        // Error: any server or network error
    }
}
val request = FinishSignupRequest(
    flowId = flowId,
    password = password,
    email = email,
    name = null,
    firstName = firstName,
    lastName = lastName,
    phoneNumber = phoneNumber
)
return vipasoPay.finishSignupFlow(request) // Success returns flowId

HTTP request and response in the background:

POST /a/self-service/registration?flow=ef23c1db-0000-4022-873c-cf26fc1372fa HTTP/1.1
Content-Type: application/json
{
  "method": "password",
  "traits": {
    "name": {
      "first": "Pay User",
      "last": "Test"
    },
    "phone": "+439999999999"
  },
  "password": "000000"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
  "session_token": "vip_st_VRRNobsaHTz3sHGqkWbk5JAV11e1OaBO",
  "session": {
    "identity": {
      "id": "9a8cbfb3-87bd-0000-b48d-2569b1b43386",
      ...
    },
    ...
  },
  ...
}

Example screenshots from our development application:

Note: In the end the SDK will automatically generate and save a local key pair and send the public key to the backend. This needs to happen for the user to be considered logged in. You will see a PUT request to /identity/pki/client/certificates at the end of the flow.

4. Observing authentication state changes

Important: The SDK will not expose the session token to the client side. Instead, it will store it internally and will emit an update to notify the app (via VipasoPayDelegate or VipasoPayListener) about the changed authentication state.

extension YourViewCoordinator: VipasoPayDelegate {

    func onAuthenticationStateChange(vipaso: VipasoPayProtocol, authenticated: Bool) {
        if authenticated {
            // Your user is logged in
        } else {
            // Your user got logged out (can be automatic after 401 or manually calling logout)
        }
    }
}
class AuthenticationManager(): VipasoPayListener {

    override fun onAuthenticationStateChange(authenticated: Boolean) {
        if (authenticated) {
            // Your user is logged in
        } else {
            // Your user got logged out (can be automatic after 401 or manually calling logout)
        }
    }
}

What’s Next