Device Swap
Provide real-time insights into whether a SIM card associated with a user’s phone number has been transferred to a different physical device.
Introduction
The Device Swap API performs real-time checks on the last Device Swap event, providing real-time information about whether the SIM card associated with a user's phone number has been transferred to a different physical device.
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 SIM swap 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 back channel authorization from the application
To authenticate the end-user a POST request must be sent to the bc-authorize endpoint from the user device. This request must provide required parameters.
Note: As this API is used only for Fraud prevention & detection purpose an explicit consent is not mandated. The autorisation server will check if the user has opted-out the permission to communicate this data.
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.
For current implementation FraudPreventionAndDetection dpv value is managed, which means that:
- to check the Device Swap date, the scope in the
bc-authorizemust be set toopenid dpv:FraudPreventionAndDetection device-swap - to check the Device Swap max age, the scope in the
bc-authorizemust be set toopenid dpv:FraudPreventionAndDetection device-swap.
(NB : please note that current implementation only supports global scope "device-swap").
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
curl -X POST "https://api.orange.com/es/openapi/oauth/v2/bc-authorize" \
--header 'Accept: application/json' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'login_hint=tel:+346xxxxxxxx' \
--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:FraudPreventionAndDetection device-swap'
The Orange authorization server will send back to the client application an authorization req_id.
200
Content-Type: application/json
{
"auth_req_id":"69957d77-fea4-4a4c-8cd2-b29f22e61307",
"interval":2,
"expires_in": 120
}
Note: this authorization code is provided even if the end user opted-out.
Step 2: Request the OAuth access token
Once the client application got the authorization code, it has to get the access token protecting the resource. In order to retrieve it, the client application triggers a POST request to the token endpoint.
curl -X POST "https://api.orange.com/es/openapi/oauth/v2/token"
--header 'Accept: application/json' \
--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-fea4-4a4c-8cd2-b29f22e61307' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
If the transaction succeeds, in the POST response, the acccess_token is provided.
200
Content-Type: application/json
{
"access_token":"*****",
"token_type":"Bearer",
"expires_in": 119
}
Step 3: Access protected resources using OAuth access token
In order to call our API, the access_token is mandatory.
Specific documentation about Device Swap resources is provided below.
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.comcamara/oes/device-swap/v0
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 two resources which have their own parameters.
/retrieve-date (POST)
This service returns the timestamp of the most recent device change, capturing the latest alteration between a specific mobile phone number (identified by the SIM card associated) and its device.
Request
| Parameter | Description | Usage | Location | Type |
|---|---|---|---|---|
phoneNumber | Subscriber number in E.164 format (starting with country code). Optionally prefixed with '+'. | Mandatory | body | String |
As an example:
curl
--request POST \
--header 'Authorization: Bearer *****' \
--data '{"phoneNumber": "+34654654654"}'
'https://api.orange.com/camara/oes/device-swap/v0.1/retrieve-date'
Response
a/ If the transaction succeeds
On success, the DeviceSwap API returns a 200 OK HTTP status code with JSON data including the 'latestDeviceChange' property with information about device swap change.
| Parameters | Description | Usage | Location | Type |
|---|---|---|---|---|
| latestDeviceChange | Timestamp of latest device swap performed, following RFC 3339 in UTC format. | Mandatory | body | String |
As an example:
200
Content-Type: application/json
{
"latestDeviceChange": "2023-09-05T13:57:55.707Z"
}
b/ If the transaction fails
Please visit the common error responses section in this page.
/check (POST)
Checks if Device swap has been performed during a past period.
Request
| Parameter | Description | Usage | Location | Type |
|---|---|---|---|---|
phoneNumber | Subscriber number in E.164 format (starting with country code). Optionally prefixed with '+'. | Mandatory | body | String |
maxAge | Period in hours to be checked for device swap. | Mandatory | body | integer |
As an example:
curl
--request POST \
--header 'Authorization: Bearer *****' \
--data '{"phoneNumber": "+34654654654","maxAge": 240}'
'https://api.orange.com/camara/oes/device-swap/v0.1/check'
Response
a/ If the transaction succeeds
On success, the DeviceSwap API returns a 200 OK HTTP status code with JSON data including the 'swapped' property indicating if device swap has been performed during the period.
| Parameters | Description | Usage | Location | Type |
|---|---|---|---|---|
| swapped | Indicates whether the device has been swapped during the period within the provided age. | Mandatory | body | boolean |
As an example:
200
Content-Type: application/json
{
"swapped": true
}
b/ If the transaction fails
Please visit the common error responses section in this page.
Common error responses
In case of error, the Device Swap API returns an error response (JSON format) with the following information:
| Parameters | Description | Usage | Location | Type |
|---|---|---|---|---|
| status | HTTP response status code | Mandatory | body | integer |
| code | Code given to this error | Mandatory | body | String |
| message | Detailed error description | Mandatory | body | integer |
This is compliant with CAMARA Project specifications, which can be read in the Device swap 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."
}
The URL of the request is right but it has been made with a method (HTTP verb) not allowed:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
{
"status": 405,
"code": "METHOD_NOT_ALLOWED",
"message": "The requested method is not allowed/supported on the target resource."
}
There is another request created for the same MSISDN:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"status": 409,
"code": "CONFLICT",
"message": "Another request is created for the same MSISDN"
}
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"
}