Table of Contents
- Table of Contents
- Authentication prerequisite
- Base URL
- Resources
- Sub resources
- ProductOrder life cycle
- ProductOrderItem life cycle
- CancelProductOrder life cycle
- Query Resources patterns
- Errors
- Use cases
- 1. I want to make an order with the productOrder API
- 2. I want to follow up my productOrder
- 3. I want to cancel an ongoing productOrder
- 4. I want to get a productOrderItem
- 5. I want to terminate an active access
- 6. I want to modify a characteristic on an active access
- 7. I want to add an optional product on an active access
- 8. I want to terminate an optional product on an active access
This document is a complement to TMF 648 documentation regarding the technical details mandated by the TM Forum applied to our application (https://www.tmforum.org/resources/specification/tmf622-product-ordering-management-api-rest-specification-r19-0-0/)
Release content October 2023
- Adding the orderTerm information in the order (#orderterm)
- Adding a comment at order level (#orderTakingNote)
- Adding new states for the order (see PO and POI lifecycle)
- Adding the trading name information (#geographicsubaddress)
- Adding the API notifications (/hub)
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:product-order:v1:readonly | Allow GET, HEAD http request for any resource of this api |
owf:united-way:product-order:v1:write | Allow POST http request for any resource of this api. PUT and DELETE http request are not available for this API. |
- If your client will only do
GET
requests, you may request anaccess_token
with '&scope=owf:united-way:product-order:v1:readonly
'. - If your client will do GET and POST requests, you must request an
access_token
with '&scope=owf:united-way:product-order:v1:readonly owf:united-way:product-order: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/product-ordering-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 |
---|---|
ProductOrder | Product Order is a type of order which can be used to place an order between a customer and a service provider or between a service provider and a partner |
ProductOrder
The below table describes the mandatory attributes required for any productorder
Name | Type / Format | Description | Example |
---|---|---|---|
productOrderSpecification | String | define the action for this ProductOrder, in case of a new configuration the value should be Acquisition , in case of Termination the value should be Termination , in case of Modification the value depends on the operationSpecification proposed in the catalog for the productOffering | Acquisition |
relatedParty | RelatedParty[] | your organization information | see below |
productOrderItem | ProductOrderItem[] | the list of ProductOrder items represents the offer you want to ProductOrder including different characteristics chosen | see below |
externalIdentifier | ExternalIdentifier[] | An ID and its informations (type, owner) given by the consumer and only understandable by him (to facilitate his searches afterwards). | see below |
Business rules for Product Order
To be set in an order, Product Order must respect several rules, otherwise the order will be rejected. See below for more details:
Code | Business error message | Description |
---|---|---|
PRO_0001_A | the productOrderSpecification is mandatory | ProductOrdeSpecification is missing, please complete this |
PRO_0002_A | The externalIdentifier is mandatory | The externalIdentifier is missing, please complete this |
PRO_0003_A | ExternalIdentifier of type CustomerIdentifier is invalid | External id is filled in several times, a unique external id is required |
PRO_0004_A | The productOrderSpecification [xxxx] is unknow | You have specified a productOrderSpecification other than those authorised |
PRO_0005_A | The ExternalIdentifier [xxxx] already exists | ExternalIdentifier already exists |
PRO_0006_A | Invalid Body field: externalIdentifier with externalIdentifierType "customer Identifier' is limited to 30 characters and must not contain space | The format of the ExternalIdentifier is not valid |
PRO_0007_A | The Note type OrderTakingNote is invalid | The OrderTakingNote has an invalid format or value null |
PRO_0008_A | Action %s is not valid | A termination is not authorized if the access is already terminated |
Business rules for Eligibility
To be set in an order, the delivery address eligibility must respect several rules, otherwise the order will be rejected. Note that the eligibility of the delivery address must be tested with the Operator eligibility France API. See below for more details:
Code | Business error message | Description |
---|---|---|
ELI_0001_A | The code IMB is mandatory for the given address | You are faced with a multi-building case, please complete the IMB code |
ELI_0002_A | This adress isn't eligible for the selected offer | The address that is not eligible for the desired offer |
ELI_0003_A | The format of address is not valid | the address format is not accepted for geographical eligibility |
Sub resources
Resource | Description |
---|---|
RelatedParty | A reference to a party playing a role in this ProductOrder (RelatedParty with role buyer). |
ProductOrderItem | A ProductOrder item describes an ordering action to be performed on a productOffering or a product |
ProductOrderItemRelationship | Used to describe relationship between ProductOrder items. |
Product | A product to be created defined by a value or an existing product defined by reference. |
ProductOffering | A product offering represents an entity that can be ordered from a provider's catalog. This sub-resource includes pricing information. |
RelatedPlaceRefOrValue | A related place defines a place described by reference or by value linked to a specific entity. |
GeographicSiteBuilding | A polymorphic entity of RelatedPlaceRefOrValue to manage address by buildingCode. |
GeographicAddress | a sub entity of GeographicSiteBuilding which contains address indications. |
GeographicSubAddress | a sub entity of GeographicAddress which contains additional indications about an address. |
ExternalIdentifier | An ExternalIdentifier which describes the unique order reference on the consumer side. |
Appointment | An appointment may be required for some orders |
Agreement | An agreement is required to post an order |
OrderTerm | An orderterm can be set to the order depending on the configuration |
Agreement
The agreement is mandatory to post an order.You need to set the number of the contract Conditions Générales Accès et Collecte. Example:
"agreement":
[
{
"id": "TESTFTTHAcess1",
"@type": "AgreementItemRef"
}
],
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String | agreement id | "TESTFTTHAcess1" | yes |
@type | String | Agreements related to current contract | "AgreementItemRef" | yes |
Business rules for Agreement
To be set in an order, the Agreement must respect several rules, otherwise the order will be rejected. See below for more details:
Code | Business error message | Description |
---|---|---|
AGR_0001_A | The agreement id is mandatory | Agreement id missing in the product offering type contract |
AGR_0002_A | The number of agreement [xxx] is unknown | Your contract is not valid, please contact your Commercial Service. |
AGR_0003_A | The product Offering is not covered by the agreement | Your contract is not valid, please contact your Commercial Service. |
AGR_0004_A | Agreement is not valid | The state of your contract is not valid, please contact your Commercial Service. |
RelatedParty
RelatedParty with role buyer
The relatedParty with the "role": "buyer"
is mandatory.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String | id of your organization | "ea69228c-600a-4058-8e4e-e13fcc8bf89f" | yes |
role | String | shoud be buyer | "buyer" | yes |
@referredType | String | shoud be organization | "organization" | yes |
name | String | name of your organization | "ABSOLIGHT" | no |
Example:
"relatedParty":[
{
"@referredType":"organization",
"id":"ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name":"ABSOLIGHT",
"role":"buyer"
}
],
To find information about your organization call the Party management API (see Party management API getting started for more information).
Example:
GET /api/v1/organization/<organizationId>
{
"id":"ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"isHeadOffice":true,
"isLegalEntity":true,
"name":"ABSOLIGHT",
"organizationType":"COMPANY",
"tradingName":"ABSOLIGHT",
"contactMedium":[],
"organizationIdentification":[
{
"identificationId":"00353831",
"identificationType":"RCE"
},
{
"identificationId":"418565404",
"identificationType":"SIREN"
}
],
"@type":"Organization",
"href":"/api/v1/organization/ea69228c-600a-4058-8e4e-e13fcc8bf89f"
}
RelatedParty with other roles
Others party can be mandatory for an order. The expected parties are listed in the catalog, depending on the offer and the type of operation (see Catalog Management API getting started for more informations).
Business rules for RelatedParty
To be set in an order, the RelatedParty must respect several rules, otherwise the order will be rejected. See below for more details:
Code | Business error message | Description |
---|---|---|
PAR_0001_A | The related party role and referred type are not conformed to the expected catalog configuration | The role of a party must correspond to the expected role given in the catalog configuration, the allowed referredType are individual or organization and the referredType |
PAR_0002_A | A buyer is mandatory in relatedParty | A relatedPartywith role buyer must be set in an order |
PAR_0003_A | The related party with role %s is mandatory for productOfferingId %s | Depending on the catalog configuration, expected parties must be set at the correspondant productOffering level |
PAR_0004_A | Individual %ID is not valid | The givenName and familyName of a relatedParty must not exceed 50 characters, the fullName 101 characters, and the \n characters are not allowed in those fields. The phone number must have a format for France and DOM TOM |
PAR_0005_A | ContactMedium Type email and phone are mandatory for individual ID% | A relatedParty with type individual must have at least a contactMedium with mediumType PHONE and MAIL |
PAR_0009_A | Order must be linked to individuals with at least two different phone number and at least two different email address | The relatedParty of the order must have at least 2 different phone numbers and 2 different email address |
ProductOrderItem
A productOrder contains a list of productOrder items, representing the desired components in terms of offer and characteristics. Like the representation of the catalog offer, the productOrder items are organised like a tree. Some productOrder items may "bundle" other productOrder items using "relationship" attributes.
- The bundling productOrder items are associated with the following catalog ProductOffering type : Contract, play, set.
- The leaf productOrder items are associated with the following catalog productOffering type : Atomic offer
Warning: If the list of productOrder items doesn't represent a tree, or if at least one productOrder item is not bundled by another one, the productOrder will be rejected.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String | unique id, used for relationship between productOrder items | "1" | yes |
action | String | can be add , modify , noChange or delete depending on productorderSpecification | "add" | yes |
productOrderItemRelationship | productOrderItemRelationship[] | Information about the relationships of the productorder item | see below | conditional |
product | ProductRefOrValue | contains informations about the desired product (exemple characteristics) | see below | conditional |
Example of productOrderItem which contains product with productOffering of type atomicOffer
and its characteristics:
...
{
"action":"add",
"id":"O40140084008",
"product":{
"productOffering":{
"id":"O40140084008",
"name":"Raccordement"
},
"productCharacteristic":[
{
"id":"FONC40140084010",
"valueType":"object",
"name":"Type de point de livraison",
"value":{
"@type":"CharacteristicChoiceValue",
"id":"VF0000140140084010",
"name":"DTIO/PTO"
}
},
{
"valueType":"object",
"id":"FONC40140084008",
"name":"Multi-accès",
"value":{
"@type":"CharacteristicChoiceValue",
"id":"VF0000240140084008",
"name":"Non"
}
},
{
"valueType":"object",
"id":"FONC40140084003",
"name":"Type de raccordement",
"value":{
"@type":"CharacteristicChoiceValue",
"id":"VF0000140140084003",
"name":"Raccordement sur prise existante"
}
},
{
"valueType":"string",
"id":"FONC40140084011",
"name":"Réfèrence PTO",
"value":"FI-9786-6362"
}
],
"productSpecification":{
"id":"PS40140084008",
"name":"Accès passif"
}
}
},
...
ProductOrderItemRelationship
Describe the relation between productOrder items.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String | id of the productOrder item wich has a relation with the current productOrder item | "1" | yes |
relationshipType | String | Relationship type | "bundles" | yes |
Example:
...
"productOrderItem":[
{
"id": 1,
"productOrderItemRelationship": [
{
"id": 2,
"relationshipType": "bundles"
},
{
"id": 3,
"relationshipType": "bundles"
}
],
...
},
{
"id": 2,
...
},
{
"id": 3,
...
}
]
...
Product
Describe the product of a productOrder item.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
place | RelatedPlaceRefOrValue | see below | (yes for the productOrderItem contract when productorderSpecification is Acquisition ) | |
productCharacteristics | Characteristic[] | key value object | see below | yes |
productOffering | ProductOfferingRef | contains information about the product offering | see below | yes |
isBundle | Boolean | true if the productorder item is bundled by another one | true | yes |
id | String | id of the product inventory asset | true | (yes in the productOrderItem contract if productorderSpecification is a value of Modification and Termination ) |
Example of product with productOffering of type contract
with the RelatedPlaceRefOrValue
of type GeographicSiteBuilding
:
...
"product":{
"isBundle":true,
"place":[
{
"@type":"GeographicSiteBuilding",
"role":"deliveryAddress",
"geographicAddress":[
{
"@type":"GeographicAddress",
"geographicSubAddress":[
{
"buildingName":"OULLINS C",
"@type":"GeographicSubAddress"
},
{
"levelNumber":"_NA_",
"levelType":"staircase",
"@type":"GeographicSubAddress"
},
{
"levelNumber":"0",
"levelType":"floor",
"@type":"GeographicSubAddress"
}
]
}
],
"buildingCode":"IMB/69149/C/ZJU1"
}
],
"productCharacteristic":[],
"productOffering":{
"id":"GOC40140084001",
"name":"FTTH ACCESS"
}
},
...
ProductOffering
Describe the product offering of a productOrder item.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String | unique id coming from Product catalog management API | "GOC40140084001" | yes |
href | String | url to get more information about the productOffering | "http://..." | no |
name | String | Description of the product offering | "FTTH ACCESS" | no |
Example:
"productOffering":{
"id":"GOC40140084001",
"name":"FTTH ACCESS"
}
RelatedPlaceRefOrValue
The RelatedPlaceRefOrValue
can be declined in various types, however, this API only manages the GeographicSiteBuilding
and GeographicAddress
TMF type.
GeographicSiteBuilding
To verify the call, you can use the Catalog APIs who drive the product.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
role | String | role of the address | "deliveryAddress" | yes |
@type | String | object type | "GeographicSiteBuilding" | yes |
buildingCode | String | building code of the the address (find with Aero API) | "IMB/69149/C/ZJU1" | yes |
geographicAddress | GeographicAddress[] | information about the geographicAddress (to set geographicSubAddress ) | see below | conditional |
To find a buildingCode
for a specific address, you should call the Operator eligibility API (see Operator eligibility France getting started form more information):
POST /api/productOfferingQualification
{
"category": {
"name": "ftth"
},
"contextType": "fulltext",
"place": {
"nonFormattedAddress": {
"fullText": "9 grande rue 69600 oullins"
}
}
}
Example: deliveryAddress
{
"place": [
{
"buildingCode": "ID-9501800009PT",
"@type": "GeographicSiteBuilding",
"geographicAddress": [
{
"cityCode": "95018",
"streetCode": "4990",
"geographicSubAddress": [
{
"levelNumber": "ESCALIER-A",
"levelType": "staircase",
"@type": "GeographicSubAddress"
},
{
"levelNumber": "ETAGE-RDC",
"levelType": "floor",
"@type": "GeographicSubAddress"
},
{
"buildingName": "BATIMENT-2",
"@type": "GeographicSubAddress"
}
],
"@type": "GeographicAddressRivoli",
"city": "ARGENTEUIL",
"postcode": "95100",
"streetName": "DE LA TOUR BILLY",
"streetNr": "2",
"streetType": "RUE",
"geographicLocation": {
"geoCodeX": "2.247034308421",
"geoCodeY": "48.945790571654",
"@type": "GeographicLocation",
"@baseType": "GeographicLocation"
},
"@baseType": "GeographicAddressRivoli"
}
],
"role": "deliveryAddress",
"@baseType": "GeographicSiteBuilding"
}
]
}
GeographicAddress
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
geographicSubAddress | geographicSubAddress[] | list of geographicSubAddress | see below | yes |
@type | String | object type | "GeographicAddress" | yes |
city | String | city name | VANVES | yes (In case of shippinAdress, otherwise the order will be rejected) |
postcode | String | ZIP code | 92170 | yes (In case of shippinAdress, otherwise the order will be rejected) |
streetName | String | street name | RABELAIS | yes (In case of shippinAdress, otherwise the order will be rejected) |
streetNr | String | street number | 14 | no |
streetType | String | street type | rue | no |
Example: shippingAddress
"place": [
{
"city":"ANTONY",
"postcode":"92160",
"streetName":"BLANCHE DE CASTILLE",
"streetNr":"16",
"streetType":"RUE",
"geographicSubAddress":[]
"@type":"GeographicAddress",
"role":"shippingAddress"
"@baseType":"GeographicAddress"
}
]
GeographicSubAddress
The
geographicSubAddress
is used to set the informationsbuilding
,staircase
,floor
andTradingName
.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
buildingName | String | building name | "OULLINS C" | conditional |
levelNumber | String | list of geographicSubAddress | "NA" , "0",... | conditional |
levelType | String | list of geographicSubAddress | "staircase" or "floor" | conditional |
subUnitNumber | String (35) | Trading name of the client | "Garage Test" | conditional |
subUnitType | String | If a tradingName is set to the order, the value of the subUnitType must be 'TradingName' | "tradingName" | conditional |
@type | String | object type | "GeographicSubAddress" | yes |
To find a GeographicSubAddress
information for a specific buildingCode, you should call the IFI API
Example of complete GeographicSiteBuilding
:
"place":[
{
"@type":"GeographicSiteBuilding",
"role":"deliveryAddress",
"geographicAddress":[
{
"@type":"GeographicAddress",
"geographicSubAddress":[
{
"buildingName":"OULLINS C",
"@type":"GeographicSubAddress"
},
{
"levelNumber":"_NA_",
"levelType":"staircase",
"@type":"GeographicSubAddress"
},
{
"levelNumber":"0",
"levelType":"floor",
"@type":"GeographicSubAddress"
},
{
"subUnitNumber": "Garage Test",
"subUnitType": "tradingName",
"@type": "GeographicSubAddress"
}
]
}
],
"buildingCode":"IMB/69149/C/ZJU1"
}
],
Business rules for Place
To be set in an order, the Place must respect several rules, otherwise the order will be rejected. See below for more details:
Code | Business error message | Description |
---|---|---|
PLA_0001_A | A place is mandatory for the productOffering | ExpectedPlace is missing in the productOffering [xxxx] |
PLA_0002_A | A Place with role [xxxx] is mandatory for the ProductOffering [xxxx] | ExpectedPlace has no role. Please, complete ExpectedPlace with role in the productOffering [xxxx] |
PLA_0003_A | The place with Type type [xxxx] is not valid | BuildingCode is missing in geographicSiteBuilding of productorderItem [xxxx], please complete the BuildingCode |
PLA_0004_A | A place is not mandatory for the productOffering [xxxx] | Please, remove place for the productOffering |
PLA_0005_A | The place type type [xxxx] is unknow | You haven't completed any Delivery Adress or Shipping Adressn please, complete a Place |
PLA_0006_A | The place with Type type [xxxx] is not valid | There are several reasons for this error : (1) The format input is not correct ; (2) Shipping Address inpunt isn't valid (city, postCode or streetName) ; (3) The role for the place's Productoffering [xxxx] is missing |
PLA_0007_A | The SubAdress is mandatory | The subAdress is missing in the productOrderItem [xxxx], please complete the SubAdress |
PLA_0008_A | % is not valid format, the delivery Address type should be % | The type of the deliveryAddress is not correct |
PLA_0009_A | Trading Name is mandatory | please complete your TradingName |
PLA_0010_A | Trading Name is not valid | Trading Name must not exceed 35 characters |
PLA_0011_A | The SubAdress is not valid | Please, complete a correct BuildingCode |
PLA_0012_A | The place with Type % is not valid | One address information is missing |
Business rules for Resources
To be set in an order, the Resources must respect several rules, otherwise the order will be rejected. See below for more details:
Code | Business error message | Description |
---|---|---|
RES_0001_A | The geographicSubAddress is not valid | ReferencePto %s does not match with the [productOrder]'s geographicSubAddresses |
RES_0002_A | The PTO reference xxx is unknow | ReferencePto %s not found for the quote's geographicSiteBuilding |
RES_0003_A | The Reference PTO is not valid | No ReferencePto found that match the productOrder's geographicSubAddresses |
RES_0005_A | GeographicSubAddress buildingName field is invalid | The buildingName is unknown in IFI |
RES_0006_A | At least one buildingName field must be present in geographicSubAddress | One buildingName must be filled |
RES_0007_A | GeographicSubAddress floor field is invalid | The floor value is unknown in IFI |
RES_0008_A | At least one floor field must be present in geographicSubAddress | One floor value must be filled |
RES_0009_A | GeographicSubAddress staircase field is invalid | The staircase value is unknown in IFI |
RES_0003_A | At least one staircase field must be present in geographicSubAddress | One staircase value must be filled |
ExternalIdentifier
The externalIdentifier with the "externalIdentifierType": "customerIdentifier"
is mandatory. Its value must not exceed 30 characters, be unique for each productOrder, and will not include the space character.
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String (30) | Unique customer order reference | "my-unique-order-ref" | yes |
externalIdentifierType | String | shoud be customerIdentifier | "customerIdentifier" | yes |
owner | String (255) | name of your organization | "ABSOLIGHT" | yes |
@type | String | shoud be ExternalIdentifier | "ExternalIdentifier" | yes |
Example:
"externalIdentifier":[
{
"id":"myExternalId",
"externalIdentifierType":"customerIdentifier",
"owner":"myOrganization",
"@type":"ExternalIdentifier"
}
]
Appointment
Name | Type / Format | Description | Example | Mandatory |
---|---|---|---|---|
id | String | appointment reference value | "IOC-BOA-44373567-0000015694579-ERDV" | yes |
href | String | url to get more information about the appointment | "http://my-appointment-url" | yes |
@type | String | shoud be AppointmentRef | "AppointmentRef" | yes |
Example:
"appointment": {
"id": "IOC-BOA-44373567-0000015694579-ERDV",
"href": "http://appointment-svc.appointment-management/api/v1/appointment/IOC-BOA-44373567-0000015694579-ERDV",
"@type": "AppointmentRef"
}
To create an appointment
, you should call the eRDV webservice (for more information, a documentation is available on your Espace opérateur: Mon compte> Mon espace documentaire).
Comment appointment: The comment of the appointment must be used to send information on the OT of the technician. You should use this comment to send information about address complement such as trading name, and also the contact of the relatedParty with role operatorDeliveryDriver (corresponding to the technical interlocutor of the operator). Note that by default, only the contact of the relatedParty with role operatorInterlocutor (operator interlocutor in charge of the follow and administration of orders) is send in the OT of the technician.
Business rules for Appointment
Others Appointment can be mandatory for an order. To be set in an order, the Appointment must respect several rules, otherwise the order will be rejected. See below for more details:
Code | Business error message | Description |
---|---|---|
APO_0001_A | The appointment ID [xxx] is not consistent with ProductOrder configuration | Several raisons for this case : (1)Product ID type of intervention incorrect characteristic. (2)The priority of the appointment is not the same in the order and in the appointment. (3)The service address is different from that indicated in the delivery address. The information relating to the appointment is incomplete (nature of the product, type of service). (4)The [xxx]deliveryWorkOrder role is not the same as the order creation role. When an appointment is created, the type of intervention must match the [xxx]role of type deliveryWorkOrder . (5)You must fill in the correct Installed Product Name |
APO_0002_A | The appointment ID [xxxx] is not valid | The appointment ID does not have a confirmed or initiated intervention. Please check the status of the intervention appointment with status [xxxx] . |
APO_0003_A | The appointment ID[xxxx] is not consistent with ProductOrder configuration | The [xxx]deliveryWorkOrder role is not the same as the order creation role. When an appointment is created, the type of intervention must match the [xxx]role of type deliveryWorkOrder . Or You must fill in the correct Installed Product Name |
APO_0004_A | The appointment ID[xxx] is not consistent with ProductOrder configuration | An appointment is expected, please enter this in the order body |
APO_0005_A | The appointment ID is not mandatory with ProductOrder configuration | In the case of a modification or cancellation, You have entered an appointment when this is not expected in the body of an order |
APO_0006_A | The appointment ID %s is not valid because it 's a test | In the case of discovery environnement, you have fictitious IDs |
APO_0007_A | The appointment ID is unknow | The appointment ID is unknown in the appointment database |
APO_0008_A | The appointment ID% was deleted | The appointment is cancelled |
OrderTerm
Depending on the configuration of the order, an orderTerm can be set (for exemple if a GTR is selected, an orderTerm is set). An orderTerm correspond to a commitment period and is a configuration defined by the API Catalog management. The orderTerm is set to the order after the order validation depending on the commitment duration selected in the order.
Example:
"itemTerm": [
{
"description": "orderterm description ?",
"duration": { "amount": 12, "units": "month", "@type": "Quantity" },
"name": "Garantie de Temps de Rétablissement",
"@type": "OrderTerm"
}
]
Name | Type / Format | Description | Mandatory |
---|---|---|---|
description | String | Description of the orderterm | yes |
@duration | String | The duration is given in month | yes |
@name | String | Name of the orderTerm | yes |
@type | String | orderterm | yes |
Note
Error note
If an error is encountered during the validation process of the order, it is rejected and an error note is added. The list of the different business error message are listed in this document.
Example:
"note": [
{
"author": "System",
"date": "2023-05-25T11:38:04+02:00",
"text": "067 The individual bbbe65f7-32d4-4539-8efe-beac37e65d0c does not have the correct role",
"@type": "errorNote"
}
]
Name | Type / Format | Description | Mandatory |
---|---|---|---|
author | String | author | yes |
date | date | Date when the error was raised | yes |
text | String | Code and message of the business error | yes |
@type | String | errorNote | yes |
Order note
You have the possibility to fill a comment when creating the order using the note
. This comment is visible by anyone reading the order. Example:
"note": [
{
"author": "Comment author",
"date": "2023-05-25T11:38:04+02:00",
"text": "Order comment",
"@type": "OrderTakingNote"
}
]
Name | Type / Format | Description | Mandatory |
---|---|---|---|
author | String | Author of the order | yes |
date | date | Date when the error was raised | yes |
text | String | Code and message of the business error | yes |
@type | String | OrderTakingNote | yes |
Notifications
Register listener
The registration of a listener is done by creating a HUB resource unique to the listener (equivalent of a subscription). The HUB resource is attached or bound to the API and its attribute specify the POST event callback address of the listener.
The hub is created via a POST api/hub call.
The POST call sets the communication endpoint address the service instance must use to deliver notifications (by default on all supported events). Note that a query expression may be supplied. The query expression may be used to filter specific event types and/or any content of the event. The query expression structure used for notification filtering is the same than the one used for queries i.e. GET.
Note that you must save the id returned at the end of the subscription as the get method is not available. The scope 'readonly' must be use to post and delete a hub.
POST /hub
Accept: application/json
{
"callback": "https://listener.com"
}
Notification available
For the API order management, the following notifications are defined:
Notifications related to ProductOrder:
- ProductOrderCreateEvent
- ProductOrderMilestoneEvent
- ProductOrderErrorMessageEvent
- ProductOrderJeopardyAlertEvent
- ProductOrderAttributeValueChangeEvent
- ProductOrderDeleteEvent
- ProductOrderStateChangeEvent
- ProductOrderInformationRequiredEvent
Notifications related to CancelProductOrder:
- CancelProductOrderCreateEvent
- CancelProductOrderStateChangeEvent
- CancelProductOrderInformationRequiredEvent
Those notifications can be used to filter events. The example below shows how to register to a listener only for productorder creation:
{
"callback": "https://listener.com",
"query":"eventType = ProductOrderCreateEvent"
}
Unregister listener
To unregister a listener, the HUB resource corresponding to the listener must be destroyed.
DELETE hub/{id}
This clears the communication endpoint address that was set by creating the Hub.
DELETE /api/hub/{id}
Accept: application/json
ProductOrder life cycle
Each ProductOrder follows a unique worklflow (state machine) with different states. See TMF documentation or below for more information.
Warning: The productOrder api delivers the productOrder asynchronously. When the productOrder is POST you get a response with the status AKNOWLEGDED.INIT. When the productOrder is being initialized, it changes to the AKNOWLEGDED.ACCEPTED status. When the productOrder is being delivered, it changes to the INPROGRESS status When the productOrder could be executed without anomaly, it will have the COMPLETED status. If a problem occurs during the delivery process, a productOrder item status may be positionned to CANCELLED, FAILED, PENDING (an action from your part is needed), HELD (temporary technical issue) and error notes will be posted at the appropriate level of the productOrder structure.
** It is not possible to PATCH the status of the productOrder. if an error has occurred on your productOrder, you must create a new one via the POST method**
ProductOrderItem life cycle
Each ProductOrder item follows a unique worklflow (state machine) with different states. See TMF documentation or below for more informations.
Warning: The Product Ordering Management API delivers the productOrder items asynchronously. When the productOrder item are POST you get a response with the status AKNOWLEGDED.INIT. When the productOrder item is being initialized, it changes to the AKNOWLEGDED.ACCEPTED status. When the productOrder item is being delivered, it changes to the INPROGRESS status When the productOrder item could be executed without anomaly, it will have the COMPLETED status. If a problem occurs during the delivery process, a productOrder item status may be positionned to CANCELLED, FAILED, PENDING (an action from your part is needed), HELD (temporary technical issue) and error notes will be posted at the appropriate level of the productOrder structure.
CancelProductOrder life cycle
Each CancelProductOrder follows a unique worklflow (state machine) with different states. See TMF documentation or below for more informations.
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 attributes.
Example:
GET /api/v1/productOrder?fields=description,orderDate
[
{
"description":"ProductOrder illustration Ariane",
"href":null,
"id":"e7dee14c-cd85-495a-9931-ef3c06f2559b",
"orderDate":"2021-07-22T11:27:22.000+02:00"
},
{
"description":"ProductOrder illustration Ariane",
"href":null,
"id":"37cf411f-5258-409a-9703-66cf965c9f43",
"orderDate":"2021-07-22T11:27:29.000+02:00"
}
]
To improve response time, only request fields that you really need. Especially when requesting a list of productOrder.
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 filtering parameters with the associated allowed operators:
- id
- description
- state
- productOrderSpecification
- href
- orderDate
- agreement.id
- agreement.href
- productOrderItem
- productOrderItem.id
- productOrderItem.product.productOffering.id
- externalIdentifier.id
- externalIdentifier
The operations available for the attributes (date, integer and string) are:
=
or.eq=
: equal to>=
or.gte=
: greater than or equal to>
or.gt=
: strictly greater than<=
or.lte=
: lower than or equal to<
or.lt=
: strictly lower than<>
or.ne=
: Not equal
Example:
GET /api/v1/productOrder?fields=state&state=INPROGRESS&orderDate.gt=2013-04-20
[
{
"href": "/api/v1/productOrder/2a89ed67-5cf8-429d-9a3d-5153d481ff55",
"id": "2a89ed67-5cf8-429d-9a3d-5153d481ff55",
"state": "INPROGRESS"
},
{
"href": "/api/v1/productOrder/7f8bb1aa-da62-41e6-be85-38b6f42827ae",
"id": "7f8bb1aa-da62-41e6-be85-38b6f42827ae",
"state": "INPROGRESS"
},
{
"href": "/api/v1/productOrder/0f9e6ecd-2bee-4448-b0cb-c6cdb29bccb7",
"id": "0f9e6ecd-2bee-4448-b0cb-c6cdb29bccb7",
"state": "INPROGRESS"
}
]
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. Be sure to read the header X-Result-Count
.
For example, to retrieve only the second element in the list
GET /api/v1/productOrder?fields=none&limit=1&offset=1
[
{
"id": "9240353c-cd38-447c-9437-9d4aa229d5ff",
"href": "/api/v1/productOrder/9240353c-cd38-447c-9437-9d4aa229d5ff"
}
]
Accept-Range
is ignored.
Sorting
The query parameter sort is used to order resources to be provided in response (used -
if you want descending).
Example:
GET /api/v1/productOrder?fields=state&sort=-orderDate
[
{
"href": null,
"id": "7f8bb1aa-da62-41e6-be85-38b6f42827ae",
"state": "INPROGRESS"
},
{
"href": null,
"id": "0f9e6ecd-2bee-4448-b0cb-c6cdb29bccb7",
"state": "INPROGRESS"
}
]
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 uses 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, 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": "...."
}
Errors 404
If you try to access to a non-existent productOrder using the following endpoint : GET productorder/{id}
:
HTTP/1.1 404 Not Found
{
"code": "60",
"message": "No entity found with ID 'sdfsd'!",
"reason": "Resource not found",
"@type": "Error"
}
Others
Below you can find a table with the http codes and their respective functional codes and messages :
HTTP error code | Quotify code error | error message |
---|---|---|
400 | 20 | Invalid URL parameter value |
400 | 21 | Missing body |
400 | 22 | Invalid body |
400 | 23 | Missing body field |
400 | 24 | Invalid body field |
400 | 25 | Missing header |
400 | 26 | Invalid header value |
400 | 27 | Missing query-string parameter |
400 | 28 | Invalid query-string parameter value |
401 | 40 | Missing credentials |
401 | 41 | Invalid credentials |
401 | 42 | Expired credentials |
403 | 50 | Access denied |
403 | 51 | Forbidden requester |
403 | 52 | Forbidden user |
403 | 53 | Too many requests |
404 | 60 | Resource not found |
405 | 61 | Method not allowed |
406 | 62 | Not acceptable |
408 | 63 | Request time-out |
409 | 69 | Conflict |
411 | 64 | Length required |
412 | 65 | Precondition failed |
413 | 66 | Request entity too large |
414 | 67 | Request-URI too long |
415 | 68 | Unsupported Media Type |
429 | 53 | Too many requests |
500 | 1 | Internal Server Error |
502 | 1 | Internal error |
502 | 3 | Bad gateway |
503 | 5 | The service is temporarily unavailable |
503 | 6 | Orange API is over capacity, retry later ! |
Use cases
1. I want to make an order with the productOrder API
I am in a sales administration team, I want to fill the needed information to send a new productorder for a product offering from sccatch. The following 3 steps are recommanded.
Understand a catalog offer
Catalog Offer Description
A catalog offer is composed of several bundles and Product Offering with relationships. A catalog offer is built in 4 levels of product offering:
- level 1: Contract
- level 2: Play
- level 3: Set
- level 4: AtomicOffer
See below an example of a possible catalog offer structuration
Contract | Play | Set | Atomic Offer | Relationships |
---|---|---|---|---|
ProductOffering Contract 1 | bundles "productOffering Play | |||
productOffering Play 1 | bundles "productOffering Set 1" | |||
productOffering Set 1 | bundles "productOffering AtomicOffer 1", "productOffering AtomicOffer 2" and "productOffering AtomicOffer 3" | |||
productOffering AtomicOffer 1 | ||||
productOffering AtomicOffer 2 | ||||
productOffering AtomicOffer 3 | ||||
productOffering Set 2 | bundles "productOffering AtomicOffer 4" | |||
productOffering AtomicOffer 4 |
Visual representation of a catalog offer
As we can see the Catalog Offer is built like a tree and some of his items are mandatory to create a productOrder, the other one are optionals.
Find a catalog offer
To generate the productOrder you must first target an offer in the catalog, this action can be done by requesting the contract
level productOffering in the catalog:
GET api/catalog/productOffering/<productOfferingId>/catalog
This request return catagories, productofferings, productSpecifications and productOfferingPrice. These elements will help you to generate the content of the productOrder.
{
"categories":[...],
"productOfferings":[...],
"productSpecifications":[...],
"productOfferingPrices":[...]
}
Building a productOrder
add mandatory attribute to the productOrder
set to the productOrder:
- "productOrderSpecification": "Acquisition"
{
"productOrderSpecification": "Acquisition",
...
}
add the related party
set your organization information into the RelatedParty (see chapter on resource relatedParty to know how to get it)
{
"externalIdentifier": [
{
"id": "myExternalId",
"externalIdentifierType": "customerIdentifier",
"owner": "myOrganization",
"@type": "ExternalIdentifier"
}
],
"instantSyncProductOrder": false,
"productorderSpecification": "Acquisition"
"relatedParty": [
{
"@referredType": "organization",
"id": "ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name": "ABSOLIGHT",
"role": "buyer"
}
],
...
}
create a productOrderItem with a productOffering
Add into the productOrderItem list a productOrderItem with:
- id: a unique id of your choice
- action: add
- a product with a productOffering from the catalog response
Example
{
"externalIdentifier": [
{
"id": "myExternalId",
"externalIdentifierType": "customerIdentifier",
"owner": "myOrganization",
"@type": "ExternalIdentifier"
}
],
"instantSyncProductOrder": false,
"productOrderSpecification": "Acquisition",
"relatedParty": [
{
"@referredType": "organization",
"id": "ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name": "ABSOLIGHT",
"role": "buyer"
}
],
"productOrderItem": [
{
"action": "add",
"id": "GOC40140084001",
"product": {
"productOffering": {
"id": "GOC40140084001",
"name": "FTTH ACCESS"
}
}
}
]
}
To find the productOffering id search it into the list of productOfferings from catalog response:
...
"productOfferings":[
{
"id":"GOC40140084001",
"href":"http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productOffering/GOC40140084001",
"name":"FTTH ACCESS",
"shortName":"FTTH ACCESS",
"category":[],
"bundledProductOffering":[],
"visible":"true",
"isTopLevel":true,
"isBundle":true,
"isFulfillable":true,
"isInstallable":true,
"productOfferingType":"contract",
"externalIdentifier":[],
"viewProperty":{},
"otherProperty":[]
},
...
create a productOrderItem with a place
To check the geographical eligibility of your productOrder, you must submit a place
of type GeographicSiteBuilding
with a buildingCode
and a role deliveryAddress
into the product
of the productOrderItem
which contains the productOffering
of type contract
.
This rule is defined by the catalog into the productOffering
of type contract
in the otherProperties
list by an element with id operationSpecification.Acquisition
which contains a value expectedPlace.deliveryAddress:geographicSiteBuilding
(see below).
{
"id":"GOC40140084001",
"href":"http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productOffering/GOC40140084001",
"name":"FTTH ACCESS",
"shortName":"FTTH ACCESS",
"productOfferingType":"contract",
...
"otherProperty":[
{
"id":"operationSpecification.Acquisition",
"multiplesValues":[
"expectedPlace.deliveryAddress:geographicSiteBuilding",
"expectedSubAddress:true"
...
},
...
]
...
}
The expectedSubAddress:true
value explains that sub address informations (building, staircase, floor) are mandatory (see chapter on resource GeographicSubAddress to know how to get it)
Example
{
"externalIdentifier": [
{
"id": "myExternalId",
"externalIdentifierType": "customerIdentifier",
"owner": "myOrganization",
"@type": "ExternalIdentifier"
}
],
"instantSyncProductOrder": false,
"productorderSpecification": "Acquisition",
"relatedParty": [
{
"@referredType": "organization",
"id": "ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name": "ABSOLIGHT",
"role": "buyer"
}
],
"productOrderItem": [
{
"action": "add",
"id": "GOC40140084001",
"product": {
"place": [
{
"@type": "GeographicSiteBuilding",
"role": "deliveryAddress",
"geographicAddress": [
{
"@type": "GeographicAddress",
"geographicSubAddress": [
{
"buildingName": "OULLINS C",
"@type": "GeographicSubAddress"
},
{
"levelNumber": "_NA_",
"levelType": "staircase",
"@type": "GeographicSubAddress"
},
{
"levelNumber": "0",
"levelType": "floor",
"@type": "GeographicSubAddress"
}
]
}
],
"buildingCode": "IMB/69149/C/ZJU1"
}
],
"productOffering": {
"id": "GOC40140084001",
"name": "FTTH ACCESS"
}
}
}
]
}
create a productOrderItem with a productOrderItemRelationship
The relation between every productOffering
with productOfferingType
: contract, play, set and atomicOffer
is done by productOrderItemRelationship
into the productOrderItem
.
If the catalog productOffering contains bundledProductOffering
like this:
{
"id":"GOC40140084001",
"href":"http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productOffering/GOC40140084001",
"name":"FTTH ACCESS",
"shortName":"FTTH ACCESS",
"productOfferingType":"contract",
...
"bundledProductOffering":[
{
"id":"OC40140084001",
"href":"http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productOffering/OC40140084001",
"name":"FTTH ACCESS"
}
],
...
add into the productOrderItem a productOrderItemRelationship
like this:
Example
{
"productorderSpecification": "Acquisition",
"relatedParty": [
{
"@referredType": "organization",
"id": "ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name": "ABSOLIGHT",
"role": "buyer"
}
],
"productOrderItem": [
{
"action": "add",
"id": "GOC40140084001",
"product": {
"place": [
{
"@type": "GeographicSiteBuilding",
"role": "deliveryAddress",
...
}
],
"productOffering": {
"id": "GOC40140084001",
"name": "FTTH ACCESS"
}
},
"productOrderItemRelationship": [
{
"id": "OC40140084001",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "OC40140084001",
"product": {
"productOffering": {
"id": "OC40140084001",
"name": "FTTH ACCESS"
}
}
}
]
}
Warning: if you add a productOrderItemRelationship into a productOrderItem you shoud add a dedicated productOrderItem for the declaration (see previous example).
create a productOrderItem with productCharacteristic
If the catalog productOffering
is a "productOfferingType":"atomicOffer"
with "isBundle":false
you should set productCharacteristic
into the product
of the productOrderItem
.
To find available characteristics for this productOffering
get the productSpecification.id
and search it into the productSpecifications
list of the catalog response (see below)
"productSpecifications":[
{
"id":"PS40140084001",
"href":"http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productSpecification/PS40140084001",
"version":"1",
"name":"Activation des ressources",
"productSpecCharacteristic":[
{
"id":"FONC40140084004",
"href":"http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productSpecCharacteristic/FONC40140084004",
"name":"Débit d'accès Montant/Descendant",
"visible":"true",
"configurable":"false",
"productSpecCharacteristicValue":[
{
"systemValueCode":"VF0000140140084004",
"value":"300M/300M",
"externalIdentifier":[
{
"referentialId":"SI_OWF",
"id":"300.0"
}
],
"property":{
"id":"VALEUR_DEBIT",
"simpleValue":"300.0"
}
},
{
"systemValueCode":"VF0000240140084004",
"value":"400M/1000M",
"externalIdentifier":[
{
"referentialId":"SI_OWF",
"id":"1000.0"
}
],
"property":{
"id":"VALEUR_DEBIT",
"simpleValue":"1000.0"
}
}
]
}
]
}
]
Example of productOrderItem with characteristics
{
"productorderSpecification":"Acquisition",
"relatedParty":[
{
"@referredType":"organization",
"id":"ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name":"ABSOLIGHT",
"role":"buyer"
}
],
"productOrderItem":[
{
"action":"add",
"id":"O40140084001",
"product":{
"productOffering":{
"id":"O40140084001",
"name":"Accès"
},
"productCharacteristic":[
{
"id":"FONC40140084004",
"valueType":"object",
"name":"Débit d'accès Montant/Descendant",
"value":{
"@type":"CharacteristicChoiceValue",
"id":"VF0000140140084004",
"name":"300M/300M"
}
},
{
"id":"FONC40140084005",
"valueType":"object",
"name":"VLAN",
"value":{
"@type":"CharacteristicChoiceValue",
"id":"VF0000240140084005",
"name":"Sans TAG"
}
}
]
}
}
]
}
Warning: If the catalog
productSpecCharacteristic
have the"valueType": "string"
theproductCharacteristic
format in the productOrderItem is:{ "id": "FONC40140084011", "valueType": "string", "name": "Référence PTO", "value": "XXXXXXXXX" }
If the catalog
productSpecCharacteristic
have aproductSpecCharacteristicValue
list, theproductCharacteristic
format in the productOrderItem is:{ "id": "FONC40140084004", "valueType": "object", "name": "Débit d'accès Montant/Descendant", "value": { "@type": "CharacteristicChoiceValue", "id": "VF0000140140084004", "name": "300M/300M" } }
create a productOrderItem with productRelationship
In special case a productOffering
need a relationship to a product from the inventory (this is the case for offers where you must have already subscribed to a product to make a quotation).
If the catalog productOffering
contains a productOfferingRelationship
you must specify a productRelationship
in the product
of the productOrderItem
.
Example of productOfferingRelationship on productOffering catalog
{
"id": "O40140084001",
"href": "http://cae-owf-ventes.caas-cnp-apps.com.intraorange/catalog/api/catalog/productOffering/O40140084001",
"name": "Accès",
"shortName": "Accès",
"visible": "true",
"productOfferingType": "atomicOffer",
"productOfferingRelationship": [
{
"id": "O40160084003",
"name": "Collecte régionale",
"relationshipType": "reliesOn",
"validFor": {
"startDate": "2000-12-31T23:00:00.000+0000"
}
},
{
"id": "O40160085001",
"name": "Collecte nationale",
"relationshipType": "reliesOn",
"validFor": {
"startDate": "2000-12-31T23:00:00.000+0000"
}
},
{
"id": "O40160086001",
"name": "Collecte DROM - métropole",
"relationshipType": "reliesOn",
"validFor": {
"startDate": "2000-12-31T23:00:00.000+0000"
}
},
...
],
...
}
To retrieve a product.id
to set in the productRelationship
of the productOrderItem
, you should call the Product Inventory Management API with this sample request based on previous sample:
GET /api/v1/product?productOffering.id=O40160084003,O40160085001,O40160086001&fields=id
[
{
"id": "2c9797447e05ac18017e252187b50025",
"href": "/api/v1/product/2c9797447e05ac18017e252187b50025"
},
{
"id": "2c9004647f69a6da017f6a1c577c0001",
"href": "/api/v1/product/2c9004647f69a6da017f6a1c577c0001"
},
...
]
After Get the reponse from inventory, choose your product.id
to set into the productRelationship
and don't forget to set the relationshipType
according the catalog relationshipType
.
Example of productOrderItem with productRelationship
{
"productorderSpecification": "Acquisition",
"relatedParty": [
{
"@referredType": "organization",
"id": "ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name": "ABSOLIGHT",
"role": "buyer"
}
],
"productOrderItem": [
{
"action": "add",
"id": "O40140084001",
"product": {
"productOffering": {
"id": "O40140084001",
"name": "Accès"
},
"productCharacteristic": [
{
"id": "FONC40140084004",
"valueType": "object",
"name": "Débit d'accès Montant/Descendant",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084004",
"name": "300M/300M"
}
},
{
"id": "FONC40140084005",
"valueType": "object",
"name": "VLAN",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000240140084005",
"name": "Sans TAG"
}
}
],
"productRelationship": [
{
"relationshipType": "reliesOn",
"product": {
"id": "2c9797447e05ac18017e252187b50025"
}
}
]
}
},
...
]
}
Create productOrder
When the content of your productOrder is completed, you can do a POST. Don't forget to use an access_token
with owf:united-way:product-order:v1:write scope.
POST /productorder
Content-Type: application/json
{
"externalIdentifier": [
{
"id": "myExternalId",
"externalIdentifierType": "customerIdentifier",
"owner": "myOrganization",
"@type": "ExternalIdentifier"
}
],
"productOrderItem": [
{
"action": "add",
"id": "GOC40140084001",
"product": {
"place": [
{
"@type": "GeographicSiteBuilding",
"role": "deliveryAddress",
"geographicAddress": [
{
"@type": "GeographicAddress",
"geographicSubAddress": [
{
"buildingName": "OULLINS C",
"@type": "GeographicSubAddress"
},
{
"levelNumber": "_NA_",
"levelType": "staircase",
"@type": "GeographicSubAddress"
},
{
"levelNumber": "0",
"levelType": "floor",
"@type": "GeographicSubAddress"
}
]
}
],
"buildingCode": "IMB/69149/C/ZJU1"
}
],
"productOffering": {
"id": "GOC40140084001",
"name": "FTTH ACCESS"
}
},
"productOrderItemRelationship": [
{
"id": "OC40140084001",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "OC40140084001",
"product": {
"productOffering": {
"id": "OC40140084001",
"name": "FTTH ACCESS"
}
},
"productOrderItemRelationship": [
{
"id": "GO40140084001",
"relationshipType": "bundles"
},
{
"id": "GO40140084002",
"relationshipType": "bundles"
},
{
"id": "GO40140084003",
"relationshipType": "bundles"
},
{
"id": "GO40140084004",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "GO40140084001",
"product": {
"productOffering": {
"id": "GO40140084001",
"name": "Caractéristiques principales"
}
},
"productOrderItemRelationship": [
{
"id": "O40140084001",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "O40140084001",
"product": {
"productOffering": {
"id": "O40140084001",
"name": "Accès"
},
"productCharacteristic": [
{
"id": "FONC40140084004",
"valueType": "object",
"name": "Débit d'accès Montant/Descendant",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084004",
"name": "300M/300M"
}
},
{
"id": "FONC40140084005",
"valueType": "object",
"name": "VLAN",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000240140084005",
"name": "Sans TAG"
}
}
],
"productRelationship": [
{
"relationshipType": "reliesOn",
"product": {
"id": "2c9797447e05ac18017e252187b50025"
}
}
]
}
},
{
"action": "add",
"id": "GO40140084002",
"product": {
"productOffering": {
"id": "GO40140084002",
"name": "Point de livraison sur site client final"
}
},
"productOrderItemRelationship": [
{
"id": "O40140084008",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "O40140084008",
"product": {
"productOffering": {
"id": "O40140084008",
"name": "Raccordement"
},
"productCharacteristic": [
{
"id": "FONC40140084010",
"valueType": "object",
"name": "Type de point de livraison",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084010",
"name": "DTIO/PTO"
}
},
{
"id": "FONC40140084008",
"valueType": "object",
"name": "Multi-accès",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000240140084008",
"name": "Non"
}
},
{
"id": "FONC40140084003",
"valueType": "object",
"name": "Type de raccordement",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084003",
"name": "Raccordement sur prise existante"
}
},
{
"id": "FONC40140084011",
"valueType": "string",
"name": "Référence PTO",
"value": "FI-9786-6362"
}
]
}
},
{
"action": "add",
"id": "GO40140084003",
"product": {
"productOffering": {
"id": "GO40140084003",
"name": "Interface de livraison sur site client final"
}
},
"productOrderItemRelationship": [
{
"id": "O40140084004",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "O40140084004",
"product": {
"productOffering": {
"id": "O40140084004",
"name": "ONT éxpédié par Orange"
},
"productCharacteristic": [
{
"id": "FONC40140084015",
"valueType": "object",
"name": "Modèle ONT",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084015",
"name": "Modèle 1 Gbps"
}
},
{
"id": "FONC40140084014",
"valueType": "object",
"name": "ONT installé par Orange",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084014",
"name": "Oui"
}
}
]
}
},
{
"action": "add",
"id": "GO40140084004",
"product": {
"productOffering": {
"id": "GO40140084004",
"name": "Intervention"
}
},
"productOrderItemRelationship": [
{
"id": "O40140084005",
"relationshipType": "bundles"
}
]
},
{
"action": "add",
"id": "O40140084005",
"product": {
"productOffering": {
"id": "O40140084005",
"name": "Intervention"
},
"productCharacteristic": [
{
"id": "FONC40140084007",
"valueType": "object",
"name": "Type d'intervention",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084007",
"name": "Standard"
}
},
{
"id": "FONC40990080002",
"valueType": "object",
"name": "Intervention",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000840990080002",
"name": "Intervention avec pose ONT : Prise Optique présente"
}
}
]
}
}
],
"relatedParty": [
{
"@referredType": "organization",
"id": "ea69228c-600a-4058-8e4e-e13fcc8bf89f",
"name": "Jean Pontus",
"role": "buyer"
}
],
"productorderSpecification": "Acquisition"
}
HTTP/1.1 201 Created
Location: /productOrder/de76cfa1-9a55-412f-a9ee-61ca2f662a63
In the response body some attributes will automatically be added, including:
- id
- href
- state (The state follows the lifecycle presented above)
- expectedFulfillmentStartDate
- expectedCompletionDate
- requestedCompletionDate
- orderDate
If the payload is not valid, server will return a 400.
HTTP/1.1 400 Bad Request
{
"code": "1",
"message": "error message",
"reason": "reason message",
"@type": "Error"
}
2. I want to follow up my productOrder
To follow the productOrder state, you can do a GET on the resource /productOrder/{id}. Don't forget to use an access_token
with owf:united-way:product-order:v1:write scope.
GET /productOrder/de76cfa1-9a55-412f-a9ee-61ca2f662a63
HTTP/1.1 200 OK
{
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
...
"state": "INPROGRESS",
...
}
ProductOrder and ProductOrderItem states
My productOrder has a state that follows the productOrder's lifecycle.
State | Type | Description |
---|---|---|
acknowledged.init | initialisation | productOrder being validated |
acknowledged.accepted | initialisation | productOrder delivery initialisation |
inProgress | delivery | productOrder ongoing delivery |
completed | final | productOrder delivered |
assessingCancellation | cancellation | productOrder cancellation request under validation |
pendingCancellation | cancellation | productOrder cancellation in progress |
cancelled | final ko | productOrder cancelled |
rejected | final ko | productOrder rejected |
failed | final ko | productOrder delivery failed |
Each productOrderItem composing my productOrder also has its own state that follows the productOrderItems's lifecycle.
State | Type | Description |
---|---|---|
acknowledged.init | initialisation | productOrderItem being validated |
acknowledged.accepted | initialisation | productOrderItem delivery initialisation |
inProgress | delivery | productOrderItem ongoing delivery |
pending | delivery | productOrderItem has encountered a delivery issue, and require an action from your side |
held | delivery | productOrderItem has encountered a delivery issue, managed by Orange |
completed | final | productOrderItem delivered |
assessingCancellation | cancellation | productOrderItem cancellation request under validation |
pendingCancellation | cancellation | productOrderItem cancellation in progress |
cancelled | final ko | productOrderItem cancelled |
rejected | final ko | productOrderItem rejected |
failed | final ko | productOrderItem delivery failed |
ProductOrder and ProductOrderItem milestones / errorMessages
During the delivery process, additional follow-up information will be provided, using milestones, errorMessages and jeopardyAlert arrays, attached to the productOrder or to the relevant productOderItem.
For example, on a productOrderItem, you mais have the following information :
{
...
"state": "inProgress",
"jeopardyAlert": [],
"milestone": [
{
"description": "Orange a bien reçu votre commande. Celle-ci est en cours de validation",
"message": "Validation de la commande en cours",
"milestoneDate": "2022-09-30T14:26:23+02:00",
"name": "FTTH",
"status": "completed",
"@type": "Milestone"
},
{
"description": "Votre commande a été validée, elle est désormais en cours de production",
"message": "En cours de production",
"milestoneDate": "2022-10-01T10:06:17+02:00",
"name": "FTTH",
"status": "completed",
"@type": "Milestone"
},
{
"message": "ICC : DSART162!10!FTT!04/05/33/0/1:835#xxx, SLID : xxxx",
"milestoneDate": "2022-10-01T10:06:17+02:00",
"name": "FTTH",
"status": "completed",
"@type": "Milestone"
}
],
"errorMessage": [
{
"message": "Suite à l'échec de l'intervention, une nouvelle étude technique est nécessaire. A l'issue de la réparation, vous pourrez reprendre un rendez-vous.",
"reason": "OWF",
"status": "closed",
"timestamp": "2022-10-14T19:06:19+02:00",
"@type": "ErrorMessage"
},
{
"message": "Suite à l'échec de l'intervention, une nouvelle étude technique est nécessaire. A l'issue de la réparation, vous pourrez reprendre un rendez-vous.",
"reason": "OWF",
"status": "opened",
"timestamp": "2022-10-14T19:06:25+02:00",
"@type": "ErrorMessage"
},
{
"message": "Rendez-vous à reprendre",
"reason": "ORT",
"status": "opened",
"timestamp": "2022-10-19T10:06:19+02:00",
"@type": "ErrorMessage"
}
],
"itemTotalPrice": [],
"@type": "ProductOrderItem"
}
- Milestones are only informational, and will always have a "completed" status
- ErrorMessages describe an issue encountered during the delivery process. An active errorMessage will have an "opened" status, which will be "closed" when the issue is solved.
- jeopardyAlerts are currently not used.
3. I want to cancel an ongoing productOrder
POST /cancelProductOrder
{
"cancellationReason": "Rétractation client",
"effectiveCancellationDate": "2021-08-25T23:03:25.098Z",
"productOrder": {
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"href": "...",
"name": "Product Order to be cancelled 5",
"@type": "ProductOrder"
},
"@type": "cancelProductOrder"
}
HTTP/1.1 201 Created
{
"id": "1",
"cancellationReason": "Rétractation client",
"effectiveCancellationDate": "2021-08-25T23:03:25.098Z",
"productOrder": {
"id": "de76cfa1-9a55-412f-a9ee-61ca2f662a63",
"href": "...",
"name": "Product Order to be cancelled 5",
"@type": "ProductOrder"
},
"@type": "cancelProductOrder"
}
4. I want to get a productOrderItem
GET /productOrder/de76cfa1-9a55-412f-a9ee-61ca2f662a63/productOrderItem/O40140084001
HTTP/1.1 200 OK
{
"id": "O40140084001",
"action": "add",
"state": "inProgress.accepted",
"product": {
"productOffering": {
"id": "O40140084001",
"name": "Accès"
},
"productCharacteristic": [
{
"id": "FONC40140084004",
"valueType": "object",
"name": "Débit d'accès Montant/Descendant",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000140140084004",
"name": "300M/300M"
}
},
{
"id": "FONC40140084005",
"valueType": "object",
"name": "VLAN",
"value": {
"@type": "CharacteristicChoiceValue",
"id": "VF0000240140084005",
"name": "Sans TAG"
}
}
],
"productRelationship": [
{
"relationshipType": "reliesOn",
"product": {
"id": "2c9797447e05ac18017e252187b50025"
}
}
]
}
}
5. I want to terminate an active access
To terminate an active access, a dedicated termination productOrder
must be sent.
Don't forget to use an access_token
with owf:united-way:product-order:v1:write scope.
POST /productorder
Content-Type: application/json
This termination productOrder
must include :
- characteristic : "productOrderSpecification" set to
Termination
- section : "externalIdentifier" relative to your company order
- section : "productOrderItem" of contract-level
- characteristic action set to
delete
- characteristic action set to
- section "relatedParty" relative to the
buyer
Note : you should call the Product Inventory Management API to retrieve the structure of the existing product
{
"description": "ProductOrder Résil from API - ABA",
"productOrderSpecification": "Termination",
"externalIdentifier": [
{
"id": "MYCOMPANY-ORDER-ID",
"externalIdentifierType": "customerIdentifier",
"owner": "MYCOMPANY"
}
],
"productOrderItem": [
{
"id": "2c9280828682d8590186c0abe12b06xx",
"isBundle": true,
"action": "delete",
"product": {
"id": "2c9280828682d8590186c0abe12b06xx",
"productOffering": {
"id": "GOC40140084001",
"name": "FTTH Access",
"productOfferingType": "contract"
},
"agreement": [
{
"id": "TESTFTTHAcess1"
}
],
"relatedParty": [
{
"id": "1563c17f-3c37-4c31-9642-xxxxxxxxx",
"role": "operatorInterlocutor",
"@baseType": "RelatedParty",
"@referredType": "Individual"
}
]
}
}
],
"relatedParty": [
{
"id": "8f4ac814-5072-4519-9e8c-xxxxx",
"role": "buyer",
"@referredType": "organization",
"name": "MYCOMPANY"
}
]
}
6. I want to modify a characteristic on an active access
To modify an active access SpeedCos characteristic, a dedicated modification productOrder
must be sent.
Don't forget to use an access_token
with owf:united-way:product-order:v1:write scope.
POST /productorder
Content-Type: application/json
This modification productOrder
must include :
- characteristic : "productOrderSpecification" set to
speedCosModification
- section : "externalIdentifier" relative to your company order
- section : "productOrderItem" of contract-level with action set to
noChange
- section : "productOrderItem" of play-level with action set to
noChange
- section : "productOrderItem" of set-level with action set to
noChange
- section : "productOrderItem" relative to the modified product
- characteristic action set to
modify
- the
product.id
to be modified - the new
productCharacteristic
description
- characteristic action set to
- section "relatedParty" relative to the
buyer
Note : you should call the Product Inventory Management API to retrieve the structure of the existing product
{
"description": "ProductOrder Modif speedcos from API - ABA",
"productOrderSpecification": "speedCosModification",
"externalIdentifier": [
{
"id": "MYCOMPANY_ORDER_ID",
"externalIdentifierType": "customerIdentifier",
"owner": "MYCOMPANY"
}
],
"productOrderItem": [
{
"id": "2c9280828682d8590186c084c83501cf",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c084c83501cf",
"productOffering": {
"id": "GOC40140084001"
},
"relatedParty": [
{
"id": "1563c17f-3c37-4c31-9642-xxx",
"role": "operatorInterlocutor",
"@baseType": "RelatedParty",
"@referredType": "Individual"
}
],
"agreement": [
{
"id": "TESTFTTHAcess1"
}
]
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c084c7ac01ca",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c084c7ac01ca",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c084c7ac01ca",
"productOffering": {
"id": "OC40140084001"
}
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c084c41d01c1",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c084c41d01c1",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c084c41d01c1",
"productOffering": {
"id": "GO40140084001"
}
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c084c1a101bb",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c084c1a101bb",
"quantity": 1,
"action": "modify",
"product": {
"id": "2c9280828682d8590186c084c1a101bb",
"productCharacteristic": [
{
"id": "FONC40140084004",
"name": "Débit d'accès Montant/Descendant",
"value": {
"id": "VF0000440140084004",
"name": "800M/1000M"
},
"valueType": "object"
}
],
"productOffering": {
"id": "O40140084001"
}
}
}
],
"relatedParty": [
{
"id": "8f4ac814-5072-4519-9e8c-xxx",
"role": "buyer",
"@referredType": "organization"
}
]
}
7. I want to add an optional product on an active access
To add an optional product, like a GTR, to an active access, a dedicated modification productOrder
must be sent.
Don't forget to use an access_token
with owf:united-way:product-order:v1:write scope.
POST /productorder
Content-Type: application/json
This modification productOrder
must include :
- characteristic : "productOrderSpecification" set to
gtrModification
- section : "externalIdentifier" relative to your company order
- section : "productOrderItem" of contract-level with action set to
noChange
- section : "productOrderItem" of play-level with action set to
noChange
- section : "productOrderItem" of set-level with action set to
noChange
- section : "productOrderItem" relative to the new product
- characteristic action set to
add
- the
productCharacteristic
description - the
productOffering
- characteristic action set to
- section "relatedParty" relative to the
buyer
Note : you should call the Product Inventory Management API to retrieve the structure of the existing product
{
"description": "ProductOrder ajout GTR from API - ABA",
"productOrderSpecification": "gtrModification",
"externalIdentifier": [
{
"id": "MYCOMPANY_ORDER_ID",
"externalIdentifierType": "customerIdentifier",
"owner": "MYCOMPANY"
}
],
"productOrderItem": [
{
"id": "2c9280828682d8590186c0bf9b3f0231",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c0bf9b3f0231",
"productOffering": {
"id": "GOC40140084001"
},
"relatedParty": [
{
"id": "1563c17f-3c37-4c31-9642-7b6f2533f969",
"role": "operatorInterlocutor",
"@baseType": "RelatedParty",
"@referredType": "Individual"
}
],
"agreement": [
{
"id": "TESTFTTHAcess1"
}
]
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c0bf9aa9022c",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c0bf9aa9022c",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c0bf9aa9022c",
"productOffering": {
"id": "OC40140084001"
}
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c0bf98100224",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c0bf98100224",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c0bf98100224",
"productOffering": {
"id": "GO40140084001"
}
},
"productOrderItemRelationship": [
{
"id": "GTR",
"relationshipType": "bundles"
}
]
},
{
"id": "GTR",
"quantity": 1,
"action": "add",
"product": {
"isBundle": false,
"productCharacteristic": [
{
"id": "FONC40140084009",
"name": "Type de GTR",
"value": {
"id": "VF0000240140084009",
"name": "10 heures HO (heures ouvrables)"
},
"valueType": "object"
}
],
"productOffering": {
"id": "O40140084002"
}
}
}
],
"relatedParty": [
{
"id": "8f4ac814-5072-4519-9e8c-xxx",
"role": "buyer",
"@referredType": "organization"
}
]
}
8. I want to terminate an optional product on an active access
To terminate an optional product, like a GTR, on an active access, a dedicated modification productOrder
must be sent.
Don't forget to use an access_token
with owf:united-way:product-order:v1:write scope.
POST /productorder
Content-Type: application/json
This modification productOrder
must include :
- characteristic : "productOrderSpecification" set to
gtrModification
- section : "externalIdentifier" relative to your company order
- section : "productOrderItem" of contract-level with action set to
noChange
- section : "productOrderItem" of play-level with action set to
noChange
- section : "productOrderItem" of set-level with action set to
noChange
- section : "productOrderItem" relative to the product to be terminated
- characteristic action set to
delete
- the
product.id
to be deleted
- characteristic action set to
- section "relatedParty" relative to the
buyer
Note : you should call the Product Inventory Management API to retrieve the structure of the existing product
{
"description": "ProductOrder suppression GTR from API -ABA",
"productOrderSpecification": "gtrModification",
"externalIdentifier": [
{
"id": "MYCOMPANY_ORDER_ID",
"externalIdentifierType": "customerIdentifier",
"owner": "MYCOMPANY"
}
],
"productOrderItem": [
{
"id": "2c9280828682d8590186c09e1ff401f1",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c09e1ff401f1",
"productOffering": {
"id": "GOC40140084001"
},
"relatedParty": [
{
"id": "1563c17f-3c37-4c31-9642-xxx",
"role": "operatorInterlocutor",
"@baseType": "RelatedParty",
"@referredType": "Individual"
}
],
"agreement": [
{
"id": "TESTFTTHAcess1"
}
]
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c09e1f4401ec",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c09e1f4401ec",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c09e1f4401ec",
"productOffering": {
"id": "OC40140084001"
}
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c09e1be201e3",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c09e1be201e3",
"quantity": 1,
"action": "noChange",
"product": {
"id": "2c9280828682d8590186c09e1be201e3",
"productOffering": {
"id": "GO40140084001"
}
},
"productOrderItemRelationship": [
{
"id": "2c9280828682d8590186c09e184301df",
"relationshipType": "bundles"
}
]
},
{
"id": "2c9280828682d8590186c09e184301df",
"quantity": 1,
"action": "delete",
"product": {
"id": "2c9280828682d8590186c09e184301df",
"productOffering": {
"id": "O40140084002"
}
}
}
],
"relatedParty": [
{
"id": "8f4ac814-5072-4519-9e8c-xxx",
"role": "buyer",
"@referredType": "organization"
}
]
}