Table of Contents
- Table of Contents
- Authentication prerequisite
- Base URL
- Resources
- Query resources patterns
- Errors
- Use cases
This document is a complement to TMF 637 documentation regarding the technical details mandated by the TM Forum applied to our application (https://www.tmforum.org/resources/standard/tmf637-product-inventory-management-api-rest-specification-r19-0-0/)
Authentication prerequisite
Access to this API is secured by the OAuth 2.0 framework with the Client Credentials grant type, which means that you will have to present an OAuth 2.0 access_token
whenever you want to request this API.
It's easy to negotiate this access_token
: just send a request to the proper token negotiation endpoint, with a Basic Authentication header valued with your own client_id
and client_secret
.
For this API, the token negotiation endpoint is: https://api.orange.com/oauth/v3/token
.
A technical guide is available to learn how to negotiate and manage these access_token
.
SDK to manage token lifecycle could help you to implement cache token.
Scopes
Scopes restrict specific request verbs for any resource of this api. You must specify at least one when requesting for an access_token
. This is done by adding a scope
parameter within the access token request. Scopes are additive and shall be space separated.
As an example:
curl -X POST \
-H "Authorization: Basic NktSSHljksdj7P...Jjndb6UdnlrT2lOaA==" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Accept: application/json" \
-d "grant_type=client_credentials&scope=owf:united-way:scope1 owf:united-way:scope2" \
https://api.orange.com/oauth/v3/token
Scopes available in this api are explained below.
Scope | Description |
---|---|
owf:united-way:party:v1:readonly | Allow GET, HEAD http request for any resource of this api |
owf:united-way:party:v1:write | Allow POST, PUT, DELETE http request for any resource of this api |
- If your client will only do
GET
requests, you may request anaccess_token
with '&scope=owf:united-way:party:v1:readonly
'. - If your client will do GET and POST requests, you must request an
access_token
with '&scope=owf:united-way:party:v1:readonly owf:united-way:party:v1:write
'.
Scopes are not fine-grained permissions. While an access_token
can allows your client application to do GET or POST request, the request can be forbidden at the resource level.
We strongly encourage you to register a dedicated client application to subscribe to all API Place apis. You will be able to request an
access_token
with all scopes required to do a complete scenario over all needed apis.
Important
Please pay particular attention to properly handle authentication error responses in your application. See the section Errors
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 error response, please check first that the Base URL is correct.
The Base URL for this API is: https://api.orange.com/united-way/discover/party-management/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
Resource | Description |
---|---|
Organization | Retrieve a specific or a collection of organizations. |
Individual | Manage individuals and their contact information. |
Organization
Currently, only read operations are allowed. Organizations are visible from all clients. Organization do not have contactMedium
information.
Individual
Individuals of an Organization are transparently isolated from others. Thus, a client application can only see and manage Individuals of the Organization it belongs to.
Creation or modification of Individual must comply with the following rules :
familyName
andgivenName
must be set.fullName
should be set. It is used to search for individual. You MAY set its value with 'givenName
familyName
'.- at most one
contactMedium
of the samemediumType
andcharacteristic.contactType
can exist. contactMedium
must follow this rule matrix:
mediumType | characteristic.contactType | mandatory attributes |
---|---|---|
PHONE | FIXED_HOME , FIXED_OFFICE , MOBILE_HOME , MOBILE_OFFICE | phoneNumber |
PHONE | FAX | faxNumber |
MAIL | OTHER | emailAddress |
ADDRESS | SHIPPING_ADDRESS , OTHER | faxNumber |
Query resources patterns
Query Resources with attribute selection
In every GET request, you can add a fields parameters to filter the response body with a subset of the attributes.
Example:
GET /individual?fields=fullName,contactMedium.*,contactMedium.characteristic.*
[
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"fullName": "John Doe",
"contactMedium": [
{
"mediumType": "PHONE",
"preferred": true,
"characteristic": {
"contactType": "MOBILE_OFFICE",
"phoneNumber": "0600000000"
}
}
],
"href": "/individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63"
}
]
For better response time, only request fields you really need. Especially when requesting on the list endpoint.
Note that attributes id
and href
are always returned, even if fields=none
.
Query Resources with attribute filtering
According to TMF630 REST API Design Guidelines, you can filter data by specifying attributes in the querystring
. However, not all attributes can be used as a filter criteria. Herein, the exhaustive list of available parameters with the associated allowed operators:
Organization attribute filter
- name:
=
,*=
with patterns like*foo*
(corresponding to a contains pattern) - tradingName:
=
,*=
with patterns likefoo*
(corresponding to a start with pattern) or*foo*
(corresponding to a contains pattern) - isHeadOffice:
=
- isLegalEntity:
=
- nameType:
=
- organizationType:
=
and attribute value must be one ofCOMPANY
,DEPARTMENT
,UNKNOWN
. - organizationIdentification:
identificationType
andidentificationId
must be present together.identificationType
support only=
operator and attribute value shall be one ofcodeArcepRip
,rceId
,trigramRip
,siren
.identificationId
support=
operator. IfidentificationType
issiren
,identificationId
also support*=
with patterns like*123*
(corresponding to a contains pattern). See below use cases.
Individual attribute filter
- fullName:
=
,*=
with patterns likefoo*
(corresponding to a start with pattern) or*foo*
(corresponding to a contains pattern) - familyName:
=
,*=
with patterns likefoo*
(corresponding to a start with pattern) or*foo*
(corresponding to a contains pattern) - givenName:
=
,*=
with patterns likefoo*
(corresponding to a start with pattern) or*foo*
(corresponding to a contains pattern) - legalName:
=
,*=
with patterns likefoo*
(corresponding to a start with pattern) or*foo*
(corresponding to a contains pattern) - title:
=
- middleName:
=
- namePrefix:
=
- gender:
=
- partyCharacteristic:
=
.name
andvalue
must be present together andname
criteria must beCategory
. See below use cases.
For detailed information on parameters, check the API reference
Query Resources with iterators
When requesting collections, you should set pagination query parameters.
offset
: Requested index for start of resources to be provided in response requested by client.limit
: Requested number of resources to be provided in response requested by client.
After each request, explore the http headers to retrieve the number of results
X-Result-Count
: The number of matching resources in the JSON response.X-Total-Count
: The total number of matching resources.
If X-Total-Count
is bigger than X-Result-Count
, you need to request again by incrementing the offset
query parameter with the X-Result-Count
value. You can limit the number of result per page with limit
.
Note that you can't request more result per page than the default value for limit. Be sure to read the header X-Result-Count
.
For example, to retrieve only the second element in the list
GET /individual?fields=none&limit=1&offset=1
[
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"href": "/individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63"
}
]
Accept-Range
is ignored.
Sorting
The query parameter sort
is used to sort the resultset in the order specified by the fields listed as value. The default direction is ascending order, use the -
modifier to sort in descending order.
Example:
GET /organization?fields=name&offset=0&limit=2&sort=name
HTTP/1.1 200 OK
X-Result-Count: 2
X-Total-Count: 2
[
{
"id": "056a5d86-fc14-4361-94d9-014c8d7bc0fe",
"href": ".../organization/056a5d86-fc14-4361-94d9-014c8d7bc0fe",
"name": "1.0 ACOLA"
},
{
"id": "14854edb-a763-4963-b8f2-4c29be96b467",
"href": ".../organization/14854edb-a763-4963-b8f2-4c29be96b467",
"name": "118000"
}
]
Resource Individual do not support sorting.
Errors
Failure to code a proper management of the error responses in your application may affect its resilience. Access to the API may be revoked if your application generates too many mishandled errors.
Your application must parse the returned HTTP response to check if an error is returned instead of a 200 OK. Orange APIs use appropriate HTTP status codes to indicate any request processing error, providing detailed information about the underlying fault. This helps you provide better feedback to your users and implement failure recovery mechanisms in your application.
For details on the main error codes, response format, tips and troubleshooting, see our Handling API errors guide
Errors 401
If you get a status code 401
with the error code 42
(such as below), then you have to request a new access token
.
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"code": 42,
"message": "Expired credentials",
"description": "The requested service needs credentials, and the ones provided
were out-of-date."
}
Token lifetime
- Each
access_token
has a lifetime validity period. This validity period may change overtime to comply with security rules.- The token server has a maximum hourly quota per client application to prevent from misuse. Therefore, DON'T request an
access_token
each time you invoke the service API. DON'T hard-code a validity duration in your application. Instead, your application must parse the returned status code and error code to check if it needs to request a newaccess token
.
For other 401
errors: check that you provide the right Authorization
header with the right Bearer
Errors 400
In case of invalid request to the API, you will receive a 400
error code with detailed information in the body message, such as:
HTTP/1.1 400 Bad Request
{
"code": 25,
"description": "Missing header",
"message": "...."
}
Use cases
1. I want to search for my organization entity to place a quote
Other API Place apis require a relatedParty referencing my organization, for eg. placing a quote. Therefore, given a siren, I want to retrieve my organization entity to pass it to other api.
You can lookup for the organization filtering on organizationIdentification
.
GET /organization?organizationIdentification.identificationType=siren&organizationIdentification.identificationId=999999&fields=none
HTTP/1.1 200 OK
X-Result-Count: 1
X-Total-Count: 1
[
{
"id": "e7dee14c-cd85-495a-9931-ef3c06f2559b",
"href": ".../organization/e7dee14c-cd85-495a-9931-ef3c06f2559b"
}
]
2. I want to search for an individual and use it as an interlocutor to place an order
When posting an order, order api require to set a reference to a related party of the 'operatorInterlocutor'
category. I want to search for such individuals.
You can lookup for all individual within the Category
'operatorInterlocutor'
.
GET /individual?partyCharacteristic.value=operatorInterlocutor&partyCharacteristic.name=Category&fields=fullName
HTTP/1.1 200 OK
X-Result-Count: 1
X-Total-Count: 1
[
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"fullName": "Jack Dalton",
"href": "/individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63"
}
]
If the list is too big, you can refine your search with some more filter.
full name contains
'Dal'
GET /individual?partyCharacteristic.value=operatorInterlocutor&partyCharacteristic.name=Category&fullName*=*Dal*&fields=fullName
full name equals
'Jack Dalton'
GET /individual?partyCharacteristic.value=operatorInterlocutor&partyCharacteristic.name=Category&fullName=Jack%20Dalton&fields=fullName
Retrieving contactMedium
attribute is time consuming, select this field only for small resultset.
3. I want to retrieve the details of an individual or organization
Other apis expose related parties, this api can be used to get the detail of those parties.
For e.g., a fragment of a fictious order could be returned as
{
"id": "1",
"productOrderItem": [
{
"id": "c307eb1e-429d-4fa1-1338",
"quantity": 1,
"action": "add",
"product": {
"relatedParty": [
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"href": "/individuals/de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"role": "operatorInterlocutor",
"@baseType": "RelatedParty",
"@referredType": "Individual",
"@type": "RelatedParty"
}
]
}
}
],
"relatedParty": [
{
"id": "e7dee14c-cd85-495a-9931-ef3c06f2559b",
"href": "/organizations/e7dee14c-cd85-495a-9931-ef3c06f2559b",
"role": "buyer",
"@baseType": "RelatedParty",
"@referredType": "Organization",
"@type": "RelatedParty"
}
],
"@type": "ProductOrder"
}
Given the id
or href
, you can retrieve all information with a GET on the resource. If you use the id
, the attribute @referredType
can be used to discriminate the type of the related party.
For Individual
, you can use the /individual/{id}
path.
GET /individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63
HTTP/1.1 200 OK
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"familyName": "Dalton",
"fullName": "Jack Dalton",
"gender": "MALE",
"givenName": "Jack",
"contactMedium": [
{
"mediumType": "PHONE",
"preferred": true,
"characteristic": {
"contactType": "MOBILE_OFFICE",
"phoneNumber": "0600000004"
}
},
{
"mediumType": "MAIL",
"preferred": false,
"characteristic": {
"contactType": "OTHER",
"emailAddress": "jack.dalton@foo.com"
}
},
{
"mediumType": "ADDRESS",
"preferred": false,
"characteristic": {
"city": "Somewhere",
"contactType": "OTHER",
"postCode": "9999",
"street1": "21 jump street"
}
}
],
"partyCharacteristic": [
{
"name": "Category",
"valueType": "STRING",
"value": "operatorInterlocutor"
}
],
"@type": "Individual",
"href": "/individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63"
}
The same applies to Organization
with path /organization/{id}
.
4. I want to create an individual
When the individual does not exist yet, I want to create a new individual.
You can do a POST. Don't forget to use an access_token
with owf:united-way:party:v1:write
scope.
POST /individual
Content-Type: application/json
{
"familyName": "Dalton",
"fullName": "Jack Dalton",
"gender": "MALE",
"givenName": "Jack",
"contactMedium": [
{
"mediumType": "PHONE",
"preferred": true,
"characteristic": {
"contactType": "MOBILE_OFFICE",
"phoneNumber": "0600000004"
}
},
{
"mediumType": "MAIL",
"preferred": false,
"characteristic": {
"contactType": "OTHER",
"emailAddress": "jack.dalton@foo.com"
}
},
{
"mediumType": "ADDRESS",
"preferred": false,
"characteristic": {
"city": "Somewhere",
"contactType": "OTHER",
"postCode": "9999",
"street1": "21 jump street"
}
}
],
"partyCharacteristic": [
{
"name": "Category",
"valueType": "STRING",
"value": "operatorInterlocutor"
}
],
"@type": "Individual"
}
HTTP/1.1 201 Created
Location: /individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63
Content-Type: application/json
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"familyName": "Dalton",
"fullName": "Jack Dalton",
"gender": "MALE",
"givenName": "Jack",
"contactMedium": [
{
"mediumType": "PHONE",
"preferred": true,
"characteristic": {
"contactType": "MOBILE_OFFICE",
"phoneNumber": "0600000004"
}
},
{
"mediumType": "MAIL",
"preferred": false,
"characteristic": {
"contactType": "OTHER",
"emailAddress": "jack.dalton@foo.com"
}
},
{
"mediumType": "ADDRESS",
"preferred": false,
"characteristic": {
"city": "Somewhere",
"contactType": "OTHER",
"postCode": "9999",
"street1": "21 jump street"
}
}
],
"partyCharacteristic": [
{
"name": "Category",
"valueType": "STRING",
"value": "operatorInterlocutor"
}
],
"@type": "Individual",
"href": "/individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63"
}
If the payload is not valid, the server will return a 400
.
HTTP/1.1 400 Bad Request
{
"code": "23",
"message": "The field familyName is required",
"reason": "Missing body field",
"@type": "Error"
}
5. I want to update an individual
You can do a PATCH. Don't forget to use an access_token
with owf:united-way:party:v1:write
scope.
PATCH /individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63
Content-Type: application/json
{
"fullName": "Joe Dalton",
"givenName": "Joe",
"contactMedium": [
{
"mediumType": "ADDRESS",
"preferred": true,
"characteristic": {
"city": "Paris",
"contactType": "OTHER",
"postCode": "75002",
"street1": "1 rue de la paix"
}
}
],
"partyCharacteristic": [
{
"name": "Category",
"valueType": "STRING",
"value": "operatorInterlocutor"
}
]
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"familyName": "Dalton",
"fullName": "Joe Dalton",
"gender": "MALE",
"givenName": "Joe",
"contactMedium": [
{
"mediumType": "ADDRESS",
"preferred": true,
"characteristic": {
"city": "Paris",
"contactType": "OTHER",
"postCode": "75002",
"street1": "1 rue de la paix"
}
}
],
"partyCharacteristic": [
{
"name": "Category",
"valueType": "STRING",
"value": "operatorInterlocutor"
}
],
"@type": "Individual",
"href": "/individual/de76cfa1-9a55-412f-a9ee-61ca2f662a63"
}
Note that patching arrays like partyCharacteristic
or contactMedium
is a replace all operation.