KYC Age Verification

The KYC Age Verification API provides the ability to check if the user of the line is older than a provided age.

Marketing
Anti-Fraud
Network API
Camara

Introduction

The KYC Age Verification API provides the customer with the ability to check if the user of the line is older than 18 year old, in order to provide API customer's age-restricted services, access to its age-restricted website etc..

API Scope

The current API implementation is applicable to any mass-market masOrange, jazztel customers.

Subscribe to the API

You have to register your application on the Orange Developer Console and subscribe to it.

API Authentication

HTTPS requests to the REST API are protected with CIBA 3-Legged OAuth.

In short, the API Invoker (e.g. Application Backend or Aggregator) before to request KYC Age Verification check, needs to request a Three-Legged Access Token from Orange Authorization Server. The process follows the OpenID Connect Client-Initiated Backchannel Authentication (CIBA) flow.

Step 1: request the OAuth authorization code from the Application Backend

The API Invoker provides in the authorization request (/bc_authorize) a login_hint with a valid User identifier together with the application credentials (client_assertion & client_assertion_type) and indicates the Purpose for processing Personal Data. The Orange implementation follows the CAMARA scope definition. The scope must be set to: opendid dpv:<dpvValue> <technicalParameter>. dpv stands for Data Privacy Vocabulary.

Note on JWT usage via client assertion: client_assertion is a JWT used by a client to authenticate itself to an authorization server, while client_assertion_type specifies the type of assertion being used, typically indicating it is a JWT. Together, they facilitate secure client authentication in OAuth 2.0 and OpenID Connect protocols. API consumer as to define JWK keystore in settings tab of the application in Orange Developer

Current supported DPV value:

  • FraudPreventionAndDetection

Example: to check the KYC Age Verification, in a context of fraud prevention and detection, the scope in the bc-authorize must be set to openid dpv:FraudPreventionAndDetection kyc-age-verification:verify

Orange Authorization Server will check if the owner of the phone number did not opted-out to authorize access to this data. If this is not the case a response 200 is sent back with a authorization request identifier (auth_req_id). If the resource owner or OpenID Provider denied the request an error 403 Forbidden is sent back.

Request:

curl  -X POST \
  'https://api.orange.com/es/openapi/oauth/v2/bc-authorize' \
  --header 'Accept: */*' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'login_hint=tel:+34654654654' \
  --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
  --data-urlencode 'client_assertion=eyJhbGciOi...zif0Tjxzw' \
  --data-urlencode 'scope=openid dpv:FulfilmentOfContractualObligation kyc-age-verification:verify'

Response:

200
Content-Type: application/json
{
  "auth_req_id": "69957d77-...-b29f22e61307",
  "expires_in": 120,
  "interval": 2
}

Step 2: Request the OAuth access token

Once the client application gets the authorization code, the API Invoker polls the token endpoint by making an "HTTP POST" request by sending the grant_type (urn:openid:params:grant-type:ciba), auth_req_id (OperatorAuthReqId) and the the application credentials (client_assertion & client_assertion_type) parameters

If the transaction succeeds, in the POST response, the acccess_token is provided.

Request:

curl  -X POST \
  'https://api.orange.com/es/openapi/oauth/v2/token' \
  --header 'Accept: */*' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
  --data-urlencode 'client_assertion=eyJhbGciOi...zif0Tjxzw' \
  --data-urlencode 'auth_req_id=69957d77-...-b29f22e61307' \
  --data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'

Response:

200
Content-Type: application/json
{
  "token_type": "Bearer",
  "access_token": "JxEA...8wmA",
  "expires_in": 179
}

Step 3: Access protected resources using OAuth access token

In order to call our API, the access_token is mandatory.

Specific documentation about KYC Age Verification resource is provided below.

API Description

Base URL

The Base URL is the first part of the full invocation URL, just before the resource paths defined in the API reference.

The Base URL is comprised of the scheme ('https'), the authority (i.e. the Fully Qualified Domain Name) and the API base path.

Whenever you request this API and encounter a 404 (Not Found) HTTP status code, please check first that the Base URL is correct.

The Base URL for this API is: https://api.orange.com/camara/oes/kyc-age-verification/v0.2

The documentation below assumes that, whenever you make requests on this API, you are prepending the Base URL to the resource paths defined for this API.

Resources

This API has one resource.

/verify (POST)

TVerify that the age of the subscriber associated with a phone number is equal to or greater than the specified age threshold value.

As it is possible that the person holding the contract and the end-user of the subscription may not be the same, the endpoint also admits a list of optional properties to be included in the request to improve the identification. The response may optionally include the identityMatchScore property with a value that indicates how certain it is that the information returned relates to the person that the API Client is requesting. Note: this feature is not available in current version.

Note: includeContentLock or includeParentalControl specific requests are not managed in this version

Request
ParameterDescriptionUsageLocationType
phoneNumberThe subscriber's phone number in E.164 format (prefixed with '+'). Must not be passed as deducted from the token.OptionalbodyString
ageThresholdThe age to compare against. Only 18 is managed for verification. Other age verification are not performed. Response will be "ageCheck": "not_available"RequiredbodyInteger
idDocumentOfficial ID number of the subscriber.OptionalbodyString
nameFull name of the customer. Not checked in this version.OptionalbodyString
givenNameCustomer's first name. Not checked in this version.OptionalbodyString
familyNameCustomer's last name. Not checked in this version.OptionalbodyString
middleNamesMiddle names of the customer. Not checked in this version.OptionalbodyString
familyNameAtBirthLast name at birth. Not checked in this version.OptionalbodyString
birthdateCustomer's birth date in ISO 8601 format (YYYY-MM-DD). Not checked in this version.OptionalbodyString
emailCustomer's email address. Not checked in this version.OptionalbodyString
includeContentLockFlag to include content lock info in response if true. Not managed in this version.OptionalbodyBoolean
includeParentalControlFlag to include parental control info if true. Not managed in this version.OptionalbodyBoolean

As an example:

curl  -X POST \
  'https://api.orange.com/camara/oes/kyc-age-verification/v0.2/verify' \
  --header 'Accept: */*' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer xxxx' \
  --data-raw '{
  "ageThreshold": 18,
  "idDocument": "66666666q",
  "name": "Federica Sanchez Arjona",
  "givenName": "Federica",
  "familyName": "Sanchez Arjona",
  "middleNames": "Sanchez",
  "familyNameAtBirth": "YYYY",
  "birthdate": "1978-08-22",
  "email": "federicaSanchez.Arjona@example.com"
}'
Response
a/ If the transaction succeeds

On success, the KYC Age V erification API returns a 200 OK HTTP status code with JSON data including the 'ageCheck' property.

ParameterDescriptionUsageLocationType
ageCheck"true" if age >= threshold, "false" if age < threshold, "not_available" if unknown or if age check required is different than 18.ReturnbodyString
verifiedStatustrue if info checked against official ID, otherwise false. NNot managed in this version.ReturnbodyBoolean
identityMatchScoreOverall confidence score (0-100). Not managed in this version.ReturnbodyInteger
contentLock"true" if content lock is active, "false" if not, "not_available" if unknown. Not managed in this version.ReturnbodyString
parentalControl"true" if parental control is active, "false" if not, "not_available" if unknown. Not managed in this version.ReturnbodyString

As an example:

HTTP/1.1 200 OK
{
  "ageCheck": "true"
}
b/ If the transaction fails

Please visit the common error responses section in this page.

This is compliant with CAMARA Project specifications, which can be read in the KYC Age Verification CAMARA documentation.

Below is a list of possible error responses.

Problem with the client request:

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "code": "INVALID_ARGUMENT",
  "message": "Client specified an invalid argument, request body or query param"
}

Authentication problem with the client request:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "status": 401,
  "code": "UNAUTHENTICATED",
  "message": "Request not authenticated due to missing, invalid, or expired credentials"
}

Client is authenticated correctly but does not have sufficient permissions:

HTTP/1.1 403 Forbidden
Content-Type: application/json
{
  "status": 403,
  "code": "PERMISSION_DENIED",
  "message": "Client does not have sufficient permissions to perform this action"
}

Resource not found (it can be an error in the pathsuffix of the URL, or an unknown phone number):

HTTP/1.1 404 Not Found
Content-Type: application/json
{
  "status": 404,
  "code": "NOT_FOUND",
  "message": "The specified resource is not found."
}

If a phoneNmmber is provided in the request:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
  "status": 422,
  "code": "UNNECESSARY_IDENTIFIER",
  "message": "The device is already identified by the access token"
}

Exceeded requests per hour/minute limit:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
  "status": 429,
  "code": "TOO_MANY_REQUESTS",
  "message": "Either out of resource quota or reaching rate limiting."
}

Generic internal server error (also used by default if the error doesn't fit any of the ones detailed in this section):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
  "status": 500,
  "code": "INTERNAL",
  "message": "Server error"
}

Service temporarily unavailable or host not reached:

HTTP/1.1 503 Service Unavailable
Content-Type: application/json
{
  "status": 503,
  "code": "UNAVAILABLE",
  "message": "Service unavailable"
}

Request time limit exceeded:

HTTP/1.1 504 Gateway Timeout
Content-Type: application/json
{
  "status": 504,
  "code": "TIMEOUT",
  "message": "Request timeout exceeded. Try later"
}