Quality On Demand

Dynamically customize and request improved network quality, ensuring better performance for critical applications, when and where it is needed.

Network Quality
Network API
Camara

Getting Started - Quality-On-Demand API

Introduction

The Quality-On-Demand (QoD) API provides a programmable interface for developers and other users (API consumers) to request stable latency or throughput managed by networks without the necessity to have an in-depth knowledge of the underlying network complexity (e.g. the 4G/5G system in case of a mobile network).

Industrial (IoT), VR/Gaming, live video streaming, autonomous driving and many other scenarios demand network communication quality and are sensitive to any change in transmission conditions. Being able to request a stable latency (reduced jitter) or prioritized throughput from the network can improve user experience substantially.

The QoD API offers application developers the capability to request stable latency (reduced jitter) or throughput for specified application data flows between application clients (within a user device) and application servers (backend services). The developer has a pre-defined set of Quality of Service (QoS) profiles which they can choose from depending on their latency or throughput requirements.

API Scope

The current API implementation is applicable to any mass-market Orange customer.

This API has few limitations:

  • for the device identifer only phone number is accepted. It is not possible to provide ip address in the request.
  • all the flows from/to this device will benefit from the quality on demand request. As such, the application server ip/port will not be considered but as providing an ip is mandatory in the CAMARA specification (a ip v4 or a v6) we expect to have an ip valued.

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 requesting Quality-On-Demand services, needs to request an Access Token from Orange Authorization Server. The process follows the OpenID Connect Client-Initiated Backchannel Authentication (CIBA) flow for 3-legged authentication.

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: openid dpv:<dpvValue> quality-on-demand:sessions:<operation>. 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 has to define JWK keystore in settings tab of the application in Orange Developer.

Current supported DPV values:

  • FulfilmentOfContractualObligation

Current supported date claims:

  • quality-on-demand:sessions:create for the POST/sessions operation
  • quality-on-demand:sessions:read For the GET/sessions/{id} operation
  • quality-on-demand:sessions:delete for the DELETE/sessions/{id} operation
  • quality-on-demand:sessions:update for the POST/sessions/{id}/extend operation
  • quality-on-demand:sessions:retrieve-by-device for the POST/retrieve-sessions operation

Examples:

  • to create a QoS session, in a context of fulfilment of contractual obligation, the scope in the bc-authorize must be set to openid dpv:FulfilmentOfContractualObligation quality-on-demand:sessions:create
  • to be able to manage all operations, in a context of fulfilment of contractual obligation, the scope in the bc-authorize must be set to openid dpv:FulfilmentOfContractualObligation quality-on-demand:sessions:retrieve-by-device quality-on-demand:sessions:update quality-on-demand:sessions:delete quality-on-demand:sessions:read quality-on-demand:sessions:create

Orange Authorization Server will check if the owner of the phone number did not opt-out to authorize access to this data. If this is not the case, a response 200 is sent back with an 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 \
  'hhttps://api.orange.com/es/openapi/oauth/v2/bc-authorize' \
  --header 'Accept: */*' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'login_hint=tel%3A%2B34665682532' \
  --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
  --data-urlencode 'client_assertion=eyJhbGciOi...zif0Tjxzw' \
  --data-urlencode 'openid dpv:FulfilmentOfContractualObligation quality-on-demand:sessions:retrieve-by-device quality-on-demand:sessions:update quality-on-demand:sessions:delete quality-on-demand:sessions:read quality-on-demand:sessions:create'

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 application credentials (client_assertion & client_assertion_type) parameters.

If the transaction succeeds, in the POST response, the access_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
{
  "access_token": "OFR_28FpNfX...7lwFAg3LR0vmHCOmJAg7Si",
  "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 Quality-On-Demand resources 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/quality-on-demand/v1

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 manages the sessions resources. Available operations allows to

  • create session
  • retrieve a session from its id
  • retrieve session without id (from phone number)
  • delete session
  • extend a session

/sessions (POST)

Create a new QoS session to manage latency/throughput priorities.

Notes:

  • The access token must be a 3-legged access token.
  • The optional device identifier MUST NOT be provided, as the subject will be uniquely identified from the access token.

Request

ParameterDescriptionUsageLocationType
deviceEnd-user equipment able to connect to a mobile network. Must not be passed as the device is deducted from the token.OptionalbodyObject
device.phoneNumberThe subscriber's phone number in E.164 format (prefixed with '+').Must not be passed as the device is deducted from the tokenbodyString
device.ipv4AddressIPv4 address of the device.Not considered in our implementationbodyObject
device.ipv4Address.publicAddressPublic IPv4 address.Not considered in our implementationbodyString
device.ipv4Address.privateAddressPrivate IPv4 address.Not considered in our implementationbodyString
device.ipv4Address.publicPortPublic port number.Not considered in our implementationbodyInteger
device.ipv6AddressIPv6 address of the device.Not considered in our implementationbodyString
applicationServerA server hosting backend applications.Required - not considered in our implementation but an IP MUST be providedbodyObject
applicationServer.ipv4AddressIPv4 address of the application server. An ipv4 or ipv6 MUST be provided.OptionalbodyString
applicationServer.ipv6AddressIPv6 address of the application server. An ipv4 or ipv6 MUST be provided.OptionalbodyString
devicePortsPorts used locally by the device.Not considered in our implementationbodyObject
devicePorts.rangesRange of TCP or UDP ports.Not considered in our implementationbodyArray
devicePorts.portsArray of TCP or UDP ports.Not considered in our implementationbodyArray
applicationServerPortsPorts on the application server.Not considered in our implementationbodyObject
applicationServerPorts.rangesRange of TCP or UDP ports.Not considered in our implementationbodyArray
applicationServerPorts.portsArray of TCP or UDP ports.Not considered in our implementationnbodyArray
qosProfileA unique name for identifying a specific QoS profile. QoS Profiles are available via QoS profiles API. As of now 2 profiles are configured: TI_L_B2B and TI_S_B2BRequiredbodyString
durationRequested session duration in seconds.RequiredbodyInteger
sinkThe address to which events about status changes shall be delivered. Not managed in curent version.OptionalbodyString
sinkCredentialAuthentication information for the notification endpoint. Not managed in curent version.OptionalbodyObject
sinkCredential.credentialTypeType of credential (MUST be set to ACCESSTOKEN). Not managed in curent version.OptionalbodyString
sinkCredential.accessTokenAccess token for notification endpoint. Not managed in curent version.OptionalbodyString
sinkCredential.accessTokenExpiresUtcExpiration time of the access token. Not managed in curent version.OptionalbodyString
sinkCredential.accessTokenTypeType of access token (MUST be set to bearer). Not managed in curent version.OptionalbodyString

As an example:

curl  -X POST \
  'https://api.orange.com/camara/oes/quality-on-demand/v1/sessions' \
  --header 'Accept: */*' \
  --header 'Authorization: Bearer xxxxxxx' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "applicationServer": {
      "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
    },
    "qosProfile": "TI_S_B2B",
    "duration": 60
    }
'

Response

a/ If the transaction succeeds

On success, the Quality-On-Demand API returns a 201 Created HTTP status code with JSON data including the session information.

ParameterDescriptionUsageLocationType
sessionIdSession ID in UUID format.ReturnbodyString
durationSession duration in seconds.ReturnbodyInteger
deviceDevice information (if provided in request).ReturnbodyObject
applicationServerApplication server information.ReturnbodyObject
devicePortsDevice ports (if provided in request).ReturnbodyObject
applicationServerPortsApplication server ports (if provided in request).ReturnbodyObject
qosProfileQoS profile name.ReturnbodyString
sinkNotification endpoint (if provided in request).ReturnbodyString
sinkCredentialNotification credentials (if provided in request).ReturnbodyObject
startedAtDate and time when the QoS status became "AVAILABLE".ReturnbodyString
expiresAtDate and time of the QoS session expiration.ReturnbodyString
qosStatusCurrent status of the requested QoS session (REQUESTED, AVAILABLE, UNAVAILABLE).ReturnbodyString
statusInfoReason for the new qosStatus (if applicable).ReturnbodyString

As an example:

HTTP/1.1 201 Created
{
  "device": {
    "phoneNumber": "+3466568253"
  },
  "applicationServer": {
    "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
  },
  "qosProfile": "TI_S_B2B",
  "sessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "duration": 3600,
  "startedAt": "2026-06-01T12:00:00Z",
  "expiresAt": "2026-06-01T13:00:00Z",
  "qosStatus": "AVAILABLE",
}
b/ If the transaction fails

Please visit the most frequent errors section in this page.

/sessions/{sessionId} (GET)

Get QoS session information for a specific session.

Notes:

  • The access token must be 3-legged.
  • With a 3-legged access token is used, the end user (and device) associated with the session must also be associated with the access token.
  • The session must have been created by the same API client given in the access token.

Request

ParameterDescriptionUsageLocationType
sessionIdSession ID that was obtained from the createSession operation.RequiredpathString

As an example:

curl  -X GET \
  'https://api.orange.com/camara/oes/quality-on-demand/v1/sessions/' \
  --header 'Accept: */*' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer xxxx'

Response

  • a/ If the transaction succeeds

On success, the Quality-On-Demand API returns a 200 OK HTTP status code with JSON data including the session information.

The response structure is the same as for the /sessions POST endpoint.

As an example:

HTTP/1.1 200 OK
{
  "device": {
    "phoneNumber": "+3466568253"
  },
  "applicationServer": {
    "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
  },
  "qosProfile": "TI_S_B2B",
  "sessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "duration": 3600,
  "startedAt": "2026-06-01T12:00:00Z",
  "expiresAt": "2026-06-01T13:00:00Z",
  "qosStatus": "AVAILABLE",
}
b/ If the transaction fails

Please visit the most frequent errors section in this page.

/sessions/{sessionId} (DELETE)

Delete a QoS session and release related resources.

Notes:

  • The access token is 3-legged.
  • The subject associated with the session must also be associated with the access token.
  • The session must have been created by the same API consumer given in the access token.

Request

ParameterDescriptionUsageLocationType
sessionIdSession ID that was obtained from the createSession operation.RequiredpathString

As an example:

curl  -X DELETE \
  'https://api.orange.com/camara/oes/quality-on-demand/v1/sessions/' \
  --header 'Accept: */*' \
  --header 'Authorization: Bearer xxxx'

Response

a/ If the transaction succeeds

On success, the Quality-On-Demand API returns a 204 No Content HTTP status code.

HTTP/1.1 204 No Content
b/ If the transaction fails

Please visit the most frequent errors section in this page.

/sessions/{sessionId}/extend (POST)

Extend the duration of an active QoS session.

Notes:

  • The access token is 3-legged.
  • The subject associated with the session must also be associated with the access token.
  • The session must have been created by the same API consumer given in the access token.
  • The overall duration of the QoS session, including the additional extended duration, shall not exceed the maximum duration limit fixed for the QoS Profile.

Request

ParameterDescriptionUsageLocationType
sessionIdSession ID that was obtained from the createSession operation.RequiredpathString
requestedAdditionalDurationAdditional duration in seconds to be added to the current session duration.RequiredbodyInteger

As an example:

curl  -X POST \
  'https://api.orange.com/camara/oes/quality-on-demand/v1/sessions//extend' \
  --header 'Accept: */*' \
  --header 'Authorization: Bearer xxxx' \
  --header 'Content-Type: application/json' \
  --data-raw '{ "requestedAdditionalDuration": 120 }'

Response

a/ If the transaction succeeds

On success, the Quality-On-Demand API returns a 200 OK HTTP status code with JSON data including the updated session information.

The response structure is the same as for the /sessions POST endpoint, with updated duration and expiresAt values.

As an example:

HTTP/1.1 200 OK
{
  "device": {
    "phoneNumber": "+3466568253"
  },
  "applicationServer": {
    "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
  },
  "qosProfile": "TI_S_B2B",
  "sessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "duration": 5400,
  "startedAt": "2026-06-01T12:00:00Z",
  "expiresAt": "2026-06-01T13:00:00Z",
  "qosStatus": "AVAILABLE",
}
b/ If the transaction fails

Please visit the most frequent errors section in this page.

/retrieve-sessions (POST)

Get QoS session information for a device.

Notes:

  • The access token is 3-legged.
  • The subject associated with the session must also be associated with the access token. In this case the optional device parameter MUST NOT be provided in the request.
  • The session must have been created by the same API consumer given in the access token.
  • If no QoS session is found for the requested device, an empty array is returned.
  • This call uses the POST method instead of GET to comply with the CAMARA Commonalities guidelines for sending sensitive or complex data in API calls.

Request

ParameterDescriptionUsageLocationType
deviceEnd-user equipment able to connect to a mobile network. Must not be passed when the device is deducted from the token.OptionalbodyObject
device.phoneNumberThe subscriber's phone number in E.164 format (prefixed with '+').OptionalbodyString
device.ipv4AddressIPv4 address of the device.OptionalbodyObject
device.ipv6AddressIPv6 address of the device.OptionalbodyString

As an example:

curl  -X POST \
  'https://api.orange.com/camara/oes/quality-on-demand/v1/retrieve-sessions' \
  --header 'Accept: */*' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer xxxx' \
  --data-raw '{}'

Response

a/ If the transaction succeeds

On success, the Quality-On-Demand API returns a 200 OK HTTP status code with JSON data including an array of session information. An empty array is returned if no sessions are found.

As an example:

HTTP/1.1 200 OK
[
{
  "device": {
    "phoneNumber": "+3466568253"
  },
  "applicationServer": {
    "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
  },
  "qosProfile": "TI_S_B2B",
  "sessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "duration": 5400,
  "startedAt": "2026-06-01T12:00:00Z",
  "expiresAt": "2026-06-01T13:00:00Z",
  "qosStatus": "AVAILABLE",
}
]

Empty response example:

HTTP/1.1 200 OK
[]
b/ If the transaction fails

Please visit the most frequent errors section in this page.

Most frequent errors

  • If invalid input is provided, in particular for the device identifier, a 400 error is triggered.
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."
}
  • If the client provided a phone number within the access token but also provides it in the API payload, an error 422 is sent back.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
  "status": 422,
  "code": "UNNECESSARY_IDENTIFIER",
  "message": "The device is already identified by the access token."
}
  • If there is a conflict with an existing session for the same device:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
  "status": 409,
  "code": "CONFLICT",
  "message": "Conflict with an existing session for the same device."
}
  • If session extension is not allowed in the current state:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
  "status": 409,
  "code": "QUALITY_ON_DEMAND.SESSION_EXTENSION_NOT_ALLOWED",
  "message": "Extending the session duration is not allowed in the current state (UNAVAILABLE). The session must be in the AVAILABLE state."
}

There are some cases where your client application will no longer gain access to API resources, and get an error back.

Please check the following points:

  • Here, you attempt to use an expired or revoked access_token and you get an invalid token error. You will have to request a new access_token. As an example:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "status": 401,
  "code": "UNAUTHENTICATED",
  "message": "Request not authenticated due to missing, invalid, or expired credentials. A new authentication is required."
}
  • Here, you removed your subscription to the API so that the capability to generate an access_token is not allowed anymore. As an example:
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 path suffix of the URL, or an unknown session ID):
HTTP/1.1 404 Not Found
Content-Type: application/json
{
  "status": 404,
  "code": "NOT_FOUND",
  "message": "The specified resource is not found."
}
  • Device identifier not found:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
  "status": 404,
  "code": "IDENTIFIER_NOT_FOUND",
  "message": "Device identifier not found."
}
  • Exceeded requests per hour/minute limit:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
  "status": 429,
  "code": "TOO_MANY_REQUESTS",
  "message": "Rate limit reached."
}