Result Endpoint
We're almost there! The final step is to get the result of your phone verification process. Similarly to how you start a verification, this process will require you to build a Result Endpoint that lets your apps know how to proceed once it finishes. The expected behavior for mobile and web is different, mainly because the web version uses a mechanism similar to OAuth 2.0 and relies on a callback URL you configure where our service will redirect once the verification flow is complete.
Nonetheless, we expect this request to land on your server, not your web app or website. This way, we can ensure that your server is authoritative and the single source of truth regarding how to proceed after a verification process has ended.
On the other hand, an implementation for mobile apps uses a traditional web service that the app can access to determine what to do next.
Step 1: Create the Endpoint
With this in mind, following the specification below, you'll need to create an endpoint in your API or backend with a name like api.example.com/verification-result
.
If you are working with a web app, please remember to set its URL as the callback for your API Key in the Veriph.One dashboard.
Specification
api.example.com/verification-result
- Web-Only
- Mobile-Only
- Mixed (Reusable)
Method
GET
Parameters
Appended to the URL as query params.
Name | Required | Type | Description |
---|---|---|---|
sessionUuid | Yes | String | The UUID of the session created using the create-session endpoint. |
Responses
Code | Location | Notes |
---|---|---|
307 | URL defined by your server based on verification result. | Redirect to different locations your web app accordingly. |
Notes
The endpoint needs to be publicly accessible since the request will be coming from your user's browser.Step 2: Request the verification result
Inside this endpoint, you'll need to connect to our API via the verification-result
web service using your API Key, Secret, and session UUID (the one you got as a query param). This web service will return all data points relevant to the phone verification process, including the firstSuccessfulAttempt
object that can help you quickly determine if the process was successful (it'll be null in case it wasn't). Verifications are not successful when:
- The user tried to tamper with the verification process.
- The user tried to use a different phone number for MFA/2FA than the one sent by your server.
- Your client was disabled due to billing, legal, or administrative reasons.
As you can see, this endpoint relies on your API key's secret to respond, which is another crucial reason why this process needs to happen on your server. Your secret is the only way to query your phone verification results; someone could access your users' phone numbers if compromised. Keep your secret safe, and never commit it to your repository or make it accessible to client-executable code.
Parsing the status
To determine the exact reasons for an error or ensure that the verification process went smoothly, you'll need to parse the status of the first successful attempt, or the last attempt in the list when there is none. This process is quite simple and only requires some bitwise operations to extract the complete picture. Below, you'll find some code examples on how to do so, and remember to review the complete list of statuses here.
Phone verification results can update over time, especially when bad actors try to circumvent our security measures. Rest assured that when we call your endpoint, the result is definitive; it's either valid or invalid, and that won't change. However, the verification status updates multiple flags whenever users or bots reuse the codes and UUIDs. We use these updates for fraud detection and reputation scores.
- Typescript
- Go
class VeriphOneResult {
isOpen: boolean = false;
wasSuccessful: boolean = false;
hasErrors: boolean = false;
errorDestinationMismatch: boolean = false;
errorOriginMismatch: boolean = false;
errorInvalidated: boolean = false;
errorExpired: boolean = false;
errorClientDisabled: boolean = false;
errorMethodTampering: boolean = false;
errorTooManySubmissions: boolean = false;
errorExceededAttemptQuota: boolean = false;
errorUserCancelledAttempt: boolean = false;
}
function parseStatus(status: number): VeriphOneResult {
const result = new VeriphOneResult();
if (status === 0) {
result.isOpen = true;
return result;
}
result.wasSuccessful = (status & 0b10000000000000) > 0;
result.hasErrors = (status & 0b01111111111111) > 0;
if (!result.hasErrors) return result;
result.errorDestinationMismatch = (status & 0b00000000000001) > 0;
result.errorOriginMismatch = (status & 0b00000000000010) > 0;
result.errorInvalidated = (status & 0b00000000000100) > 0;
result.errorExpired = (status & 0b00000000001000) > 0;
result.errorClientDisabled = (status & 0b00000000010000) > 0;
result.errorMethodTampering = (status & 0b00000000100000) > 0;
result.errorTooManySubmissions = (status & 0b00000001000000) > 0;
result.errorExceededAttemptQuota = (status & 0b00000010000000) > 0;
result.errorUserCancelledAttempt = (status & 0b00000100000000) > 0;
return result;
}
type VeriphOneResult struct {
IsOpen bool
WasSuccessful bool
HasErrors bool
ErrorDestinationMismatch bool
ErrorOriginMismatch bool
ErrorInvalidated bool
ErrorExpired bool
ErrorClientDisabled bool
ErrorMethodTampering bool
ErrorTooManySubmissions bool
ErrorExceededAttemptQuota bool
ErrorUserCancelledAttempt bool
}
func parseStatus(status int) VeriphOneResult {
var result VeriphOneResult
if status == 0 {
result.IsOpen = true
return result
}
result.WasSuccessful = status & 0b10000000000000 > 0
result.HasErrors = status & 0b01111111111111 > 0
if !result.HasErrors {
return result
}
result.ErrorDestinationMismatch = status & 0b00000000000001 > 0
result.ErrorOriginMismatch = status & 0b00000000000010 > 0
result.ErrorInvalidated = status & 0b00000000000100 > 0
result.ErrorExpired = status & 0b00000000001000 > 0
result.ErrorClientDisabled = status & 0b00000000010000 > 0
result.ErrorMethodTampering = status & 0b00000000100000 > 0
result.ErrorTooManySubmissions = status & 0b00000001000000 > 0
result.ErrorExceededAttemptQuota = status & 0b00000010000000 > 0
result.ErrorUserCancelledAttempt = status & 0b00000100000000 > 0
return result
}
Step 3: Decide what to do next
Now that you have a result, you can store it if needed, but most importantly, you must decide what should happen next in your app's user interface. Here are some examples of actions you could take:
- If the user is going through an onboarding or KYC flow and the verification is successful, you may show the next step in the process or send the user to the home screen in case it has ended.
- If the result is negative, you should show an error, interrupt the undergoing transaction, or return to the start of the flow.
Some users might not finish the verification flow because they were interrupted, distracted, or decided not to continue the operation. In this case, little action can be taken (especially when the user goes idle), so don't assume we'll call your endpoint in 100% of the cases.
Web
The process should be as efficient and fast as possible. Remember that your users see this as a redirection, and their browser is currently on a blank screen waiting for your server to respond.
Once you've decided what to do next, you must respond with an HTTP redirection code (as you know, we recommend 307) and the new location URL to render the result. This URL can be whatever fits your needs and can be managed entirely by your client-side code if you desire.
If your server needs to return an error, avoid responding with anything different than the HTTP code 307 (more on this in the next section). If you do, the browser won't render the website, leaving your user with little to no information on what happened. The best way to handle this is to redirect to your web app with sufficient data to render the error or decide what to do next.
Mobile
Regardless of successful verification, your server should respond to a request by building an object that the app can use to determine how to proceed with the result. If something goes wrong, return an error; otherwise, the app should get sufficient data to continue with the transaction or process that was happening before the verification started.
Next steps
That's it! You've reached the last step of the integration; let's review what you have done so far:
- Your web or mobile apps can trigger the verification flow by calling your
Start Endpoint
. - Your server is notified when a verification result is ready. Then, you can ask our API for the result so you can store and process it as needed.
- Your web or mobile apps receive instructions from your back end to determine the steps to take after a verification process finishes.
Your server is ready to expose these endpoints to your apps, allowing total integration with our SDKs!
Support
Questions? Comments? Something is missing? If you have questions, Contact us. We welcome your feedback and suggestions.