Automatic offer provisioning

Offer provisioning

AppXite allows vendors to create and update subscriptions or cancel changes to subscriptions of end customers. It is done by sending orders of corresponding types with all the necessary instructions and data to the vendor that processes the request. We call this process “provisioning”.

Provisioning can be set up using two methods - semi-automatic (by email) and automatic. Automatic provisioning exchanges instructions and data between the platform and your fulfillment system through direct integration.

Integration Sequences

What are sequences

The integration between the platform and the vendor system consists of what we call "sequences" - a set of API calls in a specific order (hence, "sequence") that complete all required steps to process orders placed by the customer.

For example, if the customer makes their initial purchase of an offer, they place a purchase order – the first type of order we encounter in the lifetime of any subscription. The integration in such a case would normally contain multiple sequences that interact with the vendor’s APIs to create a customer account, enable the purchased service, set it up based on the customer’s configuration during purchase, and provide access to the service to the customer.

Default sequences

AppXite platform uses 2 kinds of Sequences, Offer-Level sequences, and Vendor-Level sequences.

  • Vendor-Level Sequences are retrieved as default sequences. These sequences will run for each offer that is related to this Vendor. For example, if Vendor A has 4 offers and only Sequences on the Vendor level, when we want to provision any offer AppXite will call the vendor sequences and process them.
  • On the other hand, if the customer has some offer-specific flows, AppXite also processes that information. The question here will come to, how AppXite decides which sequences to process.

The platform First loads Offer-Level sequences if they exist AppXite will use them. Otherwise, if AppXite will not find offer-level sequences then AppXite will call the higher-level sequences, which are the Vendor-Level sequences.

Both sequence types can be uploaded from the Product Management UI.

How to write a sequence

Integration sequence fields

Link – URL address used to query or post data to

Sequence – sequence number in a flow, used for ordering how requests will be executed. Sequences are executed in ascending order.

Params – JSON containing parameters when doing a POST, PUT, or PATCH requests – the body of the request

Method – the name of the method to be executed. Currently supported methods are “GET”, “POST”, “PUT”, “PATCH”, “DELETE”

Response – JSON containing expected response values for further processing. JSON can be queried using XPath language to record output to variables

OfferId – Platform Id of an offer to register/provision/change/cancel. Optional, when sequences are saved using a Product Management

Header – header to be included in a request. Can contain parameters.

ExecutionCondition – condition to be satisfied to execute a request. Supported conditions: not blank (keyword “#notblank“), contains value (keyword “#contains=“), not contains value (keyword "#notcontains="), and value strictly not equal (keyword "#not="). See more in the “Comparison” section of this document for more detailed descriptions and examples

ExternalMapping – used to map values in external systems such as IDs with IDs in Platform. Mapped values then can be used in future requests with the same context. For example, when provisioning a new subscription, it is possible to map this new subscription id from the vendor’s system to the one in the Platform. Mapped fields can be accessed using the notation ¦EntityName.ExternalId§

ExternalSystemId – identification of a system defined in the integration sequences, GUID, optional. Primarily used when integrating with multiple ERP/CRM/PSA systems, not used for provisioning

Comments – free text comments for the sequence

Operation – operation related to operation sequences. Currently, supported operations are listed below, operations related to provisioning are in bold:

  • PostOrder – Post a new order
  • Schedule – Process orders that cannot be provisioned immediately
  • ChangeOrder – change subscription (change quantity, etc.)
  • GetExternalData – Load External Data in the Offer – Subscription page
  • ConvertTrial – convert trial subscription
  • GetTrial – get a trial subscription

VendorId – required; when OfferId is not defined, used to filter sequences for specific Vendor and Operation.

Example

In this example, we will share Cancel Operation sequences for one of our vendors. This sequence runs when the user cancels a previously placed order in the Orders section.

{
  "IntegrationSequences": [
    {
      "Link": "https://appxite-aider-p3-test-01.azurewebsites.net/api/jwt/adobe/qa2",
      "Sequence": 5,
      "Params": "{'ResellerId':'¦Partners.TOP.OrganizationId§'}",
      "Hints": "{'EnforceUtf8': true}",
      "Method": "POST",
      "Response": "{'token':'¦Adobe.token§','clientId':'¦Adobe.clientid§','error':'¦Adobe.ErrorMsg§}",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "{'x-functions-key': 'MUST BE COMPLETED'}",
      "ExecutionCondition": "",
      "Comments": "Get token",
      "Operation": "CancelOrder",
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
      "Link": "https://partnersandbox-stage.adobe.io/v2/customers/¦DynamicParams.AdobeCustomerID§/orders/¦DynamicParams.CanceledOrderItemVendorOrderId§",
      "Sequence": 10,
      "Params": "{'status':'1008','reason':'Customer requested cancellation'}",
      "Hints": "{'EnforceUtf8': true}",
      "Method": "PATCH",
      "Response": "{'orderId':'¦DynamicParams.CanceledOrderId§','status':'¦DynamicParams.disableorderstatus§','lineItems.subscriptionId':'¦DynamicParams.VendorSubscriptionId§','code':'¦DynamicParams.disableordercode§', 'message':'¦DynamicParams.disableordermessage§'}",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "{'Authorization': 'Bearer ¦Adobe.token§','x-api-key':'¦Adobe.clientid§','X-Request-Id':'¨NewGuid()','X-Correlation-Id':'¨NewGuid()','Content-Type':'application/json','Accept':'application/json'}",
      "ExecutionCondition": "{'¦DynamicParams.AdobeCustomerID§':'#notblank','¦DynamicParams.CanceledOrderItemVendorOrderId§': '#notblank'}",
      "ExternalMapping": "",
      "ExternalSystemId": null,
      "Comments": "Submit the cancel order to Adobe",
      "Operation": "CancelOrder",
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
      "Link": "https://partnersandbox-stage.adobe.io/v2/customers/¦DynamicParams.AdobeCustomerID§/subscriptions/¦DynamicParams.VendorSubscriptionId§",
      "Sequence": 13,
      "Params": "",
      "Hints": "{'EnforceUtf8': true}",
      "Method": "GET",
      "Response": "{'status':'¦DynamicParams.subscriptionstatus§','code':'¦DynamicParams.subscriptioncode§', 'message':'¦DynamicParams.subscriptionmessage§', 'currentQuantity':'¦DynamicParams.currentQuantity§'}",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "{'Authorization': 'Bearer ¦Adobe.token§','x-api-key':'¦Adobe.clientid§','X-Correlation-Id':'¦DynamicParams.X-Correlation-Id4§','Content-Type':'application/json','Accept':'application/json'}",
      "ExecutionCondition": "{'¦DynamicParams.VendorSubscriptionId§':'#notblank'}",
      "Comments": "Get Subscription status",
      "Operation": "CancelOrder",
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
        "Link": "https://rethink-dev.eu.auth0.com/oauth/token",
        "Sequence": 50,
        "Params": "{'grant_type':'client_credentials'}",
        "Method": "POST",
        "Response": "{'access_token': '¦Header.AuthTokenHelper§'}",
        "OfferId": "00000000-0000-0000-0000-000000000000",
        "Operation": "CancelOrder",
        "Header": "{'content-type' : 'application/json'}",
        "ExecutionCondition": "",
        "Comments": ""
    },
    {
        "Link": "https://appxite-rethink-back-api-p3-test-01.azurewebsites.net/api/v1/services/subscriptions/¦Subscription.Id§/edit",
        "Sequence": 51,
        "Params": "",
        "Hints": "{\"EnforceUtf8\": true}",
        "Method": "GET",
        "Response": "{'JsonData':'¦Rethink.FormData§'}",
        "OfferId": "00000000-0000-0000-0000-000000000000",
        "Header": "{'Authorization':'Bearer ¦Header.AuthTokenHelper§','X-On-Behalf-Of':'¦Organization.Id§','Referer':'https://¦Partners.level0.Dns§'}",
        "ExecutionCondition": "{'¦Subscription.Id§':'#notblank'}",
        "Comments": "Get Subscriptions Quantity from Rethink",
        "Operation": "CancelOrder",
        "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
        "Link": "https://aiderqa.azurewebsites.net/api/Helper/tojson?code=vq6b5a3MZWV8KFO75ZKamJMZ9UJIK0WCJr1olxKhtmI3RbdplH5gvg==&clientId=ai_sequences",
        "Sequence": 52,
        "Params": "{'JSON': ¦Rethink.FormData§}",
        "Hints": "{\"EnforceUtf8\": true}",
        "Method": "POST",
        "Response": "{'priceLevelKey':'¦Rethink.Level§'}",
        "OfferId": "00000000-0000-0000-0000-000000000000",
        "Header": "",
        "ExecutionCondition": "{'¦Rethink.FormData§':'#notblank'}",
        "Comments": "convert to JSON",
        "Operation": "CancelOrder",
        "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
      "Link": "https://appxite-process-order-item-p3-test-01.azurewebsites.net/api/ProcessOrderItemEvent?code=UX8X/DIKLfkCEoe7niOLzjme4fC0VedJ1t1EBQ1rGPHRkgZ/ugnYTw==",
      "Sequence": 15,
      "Params": "{'SubscriptionStartDate': '¦DynamicParams.SubscriptionStartDate§','SubscriptionEndDate': '¦DynamicParams.SubscriptionEndDate§','SubscriptionState': 'Disabled','OrderId': '¦OrderItem.OrderId§','ProvisionStatus': '0','AssociatedPartnerId': '','LineItemNumber': '0','OfferId': '¦OfferId§','VendorId': '¦Offer.ProfileVendorId§','VendorResellerId': '','VendorCustomerId': '','FriendlyName': '¦OfferName§','Quantity': '¦FormData.LicenseQuantityKey§','SLA': '','Required': '','BundleId': '','DynamicParams': {  'Quantity': '¦DynamicParams.currentQuantity§',  'SubscriptionState': '1', 'FormData':'¦Adobe.FormData§'},'ParentSubscriptionLine': '','ParentSubscriptionId': '','VendorSubscriptionId': '¦DynamicParams.VendorSubscriptionId§','SubscriptionId': '','OrderItemId': '¦OrderItemId§','VendorOrderId': '¦DynamicParams.CanceledOrderId§','ErrorMessage': '','RequestedByUserId': '','RequestedCulture': '','CallId': '','Operation': 'CancelOrder','ApplicationId': ''}",
      "Hints": "{'EnforceUtf8':true,'ParseParams':false}",
      "Method": "POST",
      "Response": "",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "",
      "ExecutionCondition": "{'¦DynamicParams.disableorderstatus§':'1008','¦DynamicParams.currentQuantity§':'#not=0'}",
      "ExternalMapping": "",
      "ExternalSystemId": null,
      "Comments": "Cancel Success with Qty > 0",
      "RethinkMapping": null,
      "Operation": "CancelOrder",
      "VendorTenantId": null,
      "PlatformId": null,
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
      "Id": "747E49D0-DA58-4B8F-883B-0FB2920289DB",
      "Link": "https://appxite-process-order-item-p3-test-01.azurewebsites.net/api/ProcessOrderItemEvent?code=UX8X/DIKLfkCEoe7niOLzjme4fC0VedJ1t1EBQ1rGPHRkgZ/ugnYTw==",
      "Sequence": 16,
      "Params": "{'SubscriptionStartDate': '¦DynamicParams.SubscriptionStartDate§','SubscriptionEndDate': '¦DynamicParams.SubscriptionEndDate§','SubscriptionState': 'Disabled','OrderId': '¦OrderItem.OrderId§','ProvisionStatus': '0','AssociatedPartnerId': '','LineItemNumber': '0','OfferId': '¦OfferId§','VendorId': '¦Offer.ProfileVendorId§','VendorResellerId': '','VendorCustomerId': '','FriendlyName': '¦OfferName§','Quantity': '¦FormData.LicenseQuantityKey§','SLA': '','Required': '','BundleId': '','DynamicParams': {  'Quantity': '¦DynamicParams.currentQuantity§',  'SubscriptionState': '0','FormData':'¦Adobe.FormData§'},'ParentSubscriptionLine': '','ParentSubscriptionId': '','VendorSubscriptionId': '¦DynamicParams.VendorSubscriptionId§','SubscriptionId': '','OrderItemId': '¦OrderItemId§','VendorOrderId': '¦DynamicParams.CanceledOrderId§','ErrorMessage': '','RequestedByUserId': '','RequestedCulture': '','CallId': '','Operation': 'CancelOrder','ApplicationId': ''}",
      "Hints": "{'EnforceUtf8':true}",
      "Method": "POST",
      "Response": "",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "",
      "ExecutionCondition": "{'¦DynamicParams.disableorderstatus§':'1008','¦DynamicParams.currentQuantity§':'0'}",
      "Comments": "Cancel Success with 0 Qty",
      "Operation": "CancelOrder",
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
      "Id": "FEBC7410-64FE-43FA-8E61-790B7C092026",
      "Link": "https://appxite-process-order-item-p3-test-01.azurewebsites.net/api/ProcessOrderItemEvent?code=UX8X/DIKLfkCEoe7niOLzjme4fC0VedJ1t1EBQ1rGPHRkgZ/ugnYTw==",
      "Sequence": 20,
      "Params": "{'SubscriptionStartDate': '¦DynamicParams.SubscriptionStartDate§','SubscriptionEndDate': '¦DynamicParams.SubscriptionEndDate§','SubscriptionState': 'Disabled','OrderId': '¦OrderItem.OrderId§','ProvisionStatus': '3','AssociatedPartnerId': '','LineItemNumber': '0','OfferId': '¦OfferId§','VendorId': '¦Offer.ProfileVendorId§','VendorResellerId': '','VendorCustomerId': '','FriendlyName': '¦OfferName§','Quantity': '¦FormData.LicenseQuantityKey§','SLA': '','Required': '','BundleId': '','DynamicParams': {  'Quantity': '¦DynamicParams.currentQuantity§',  'SubscriptionState': '1'},'ParentSubscriptionLine': '','ParentSubscriptionId': '','VendorSubscriptionId': '¦DynamicParams.VendorSubscriptionId§','SubscriptionId': '','OrderItemId': '¦OrderItemId§','VendorOrderId': '¦DynamicParams.CanceledOrderId§','ErrorMessage': '¦DynamicParams.disableordermessage§','RequestedByUserId': '','RequestedCulture': '','CallId': '','Operation': 'schedule','ApplicationId': ''}",
        "Hints": "{'EnforceUtf8':true}",
      "Method": "POST",
      "Response": "",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "",
      "ExecutionCondition": "{'¦DynamicParams.disableordercode§':'#notblank'}",
      "Comments": "Cancel Fail",
      "Operation": "CancelOrder",
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    },
    {
      "Id": "FEBC7410-64FE-43FA-8E61-790B7C092026",
      "Link": "https://appxite-process-order-item-p3-test-01.azurewebsites.net/api/ProcessOrderItemEvent?code=UX8X/DIKLfkCEoe7niOLzjme4fC0VedJ1t1EBQ1rGPHRkgZ/ugnYTw==",
      "Sequence": 21,
      "Params": "{'SubscriptionStartDate': '¦DynamicParams.SubscriptionStartDate§','SubscriptionEndDate': '¦DynamicParams.SubscriptionEndDate§','SubscriptionState': 'Disabled','OrderId': '¦OrderItem.OrderId§','ProvisionStatus': '3','AssociatedPartnerId': '','LineItemNumber': '0','OfferId': '¦OfferId§','VendorId': '¦Offer.ProfileVendorId§','VendorResellerId': '','VendorCustomerId': '','FriendlyName': '¦OfferName§','Quantity': '¦FormData.LicenseQuantityKey§','SLA': '','Required': '','BundleId': '','DynamicParams': {  'Quantity': '¦DynamicParams.currentQuantity§',  'SubscriptionState': '1'},'ParentSubscriptionLine': '','ParentSubscriptionId': '','VendorSubscriptionId': '¦DynamicParams.VendorSubscriptionId§','SubscriptionId': '','OrderItemId': '¦OrderItemId§','VendorOrderId': '¦DynamicParams.CanceledOrderId§','ErrorMessage': '','RequestedByUserId': '','RequestedCulture': '','CallId': '','Operation': 'schedule','ApplicationId': ''}",
      "Hints": "{'EnforceUtf8':true}",
      "Method": "POST",
      "Response": "",
      "OfferId": "00000000-0000-0000-0000-000000000000",
      "Header": "",
      "ExecutionCondition": "{'¦Adobe.ErrorMsg§':'#notblank'}",
      "Comments": "Cancel Fail - Authorization Issue",
      "Operation": "CancelOrder",
      "VendorId": "02F64CF6-E340-4086-A244-315D0E61534F"
    }
  ]
}

Let's walk through what it does step by step:

  1. Sequence number 5: Here we are grabbing the Access token to access this vendor’s endpoints.
    1. Link: Holds the Endpoint’s URL.
    2. Sequence: Sequence’s order.
    3. Params: Body of the request.
    4. Method: endpoint’s Method (GET, POST, DELETE, RESPONSE).
    5. Response: Here we specify what variable we need to save in the context. In this case, we are keeping “token” and saving it in variable ¦Adobe.token§. If a variable was not in the response, it would not be saved but still, we can use ‘VariableName’:’’.
    6. OfferId: in this case, it shows that offer Id in a default GUID which says directly that these are Vendor-Level Sequences. In the perfect case, we put the OfferId of the AppXite platform.
    7. Header: Holds the information of the endpoint’s header.
    8. ExecutionCondition: Empty means that this sequence will always run, but usually we can add a combination like '¦AdobeCustomerID§':'#notblank'.
    9. Comments: Hold the description of the sequence.
    10. Operation: Holds the Operation Name.
    11. VendorId: Can be asked from support, but here is the GUID that represents the Vendor in AppXite’s platform.

So, this sequence is responsible to get the access token and save it in the context to use in the next sequences.

  1. Sequence Number 2:
    1. Sequence: 10 represents the order.
    2. Link: We can observe ¦DynamicParams.AdobeCustomerID§, ¦DynamicParams.CanceledOrderItemVendorOrderId§ these Variables will be replaced with values from the context in real-time.
    3. Execution Conditions: We can see here the set of conditions that must be met so the sequence will be processed.
    4. Method: PATCH
    5. Params: Holds the body of the request, but in this sequence, the params are hardcoded, since there are no ¦ §.

So, this sequence is responsible to PATCH an order on the vendor’s side and changing the status to 1008(Canceled).

  1. Sequence # 3: This sequence is getting the Subscription information from the Vendor and saves some values to use in the next sequences.
  2. And all sequences must be implemented in a flow to complete the communication with the Vendor.
  3. Sequence 15 until 21 generates the message we send back to AppXite that defines all the order’s information.
    1. ProvisioingStatus: 0 -> InProgress, 1->ProvisioingSuccess, 3->ProvisioingFailed
    2. OrderId: Required For all Statuses. ¦OrderItem.OrderId§
    3. OrderItemId: Required For all Statuses. ¦OrderItem.Id§
    4. OfferId: ¦LineItems[0].OfferId§
    5. VendorId: ¦LineItems[0].VendorId§
    6. VendorResellerId: ¦Partners.TOP.ExternalId§
    7. VendorCustomerId: ¦AzureTenant.ExternalId§
    8. Operation: Must be the same as the operation in the context.
    9. ErrorMessage: Holds the error Message and passes it to AppXite
    10. SubscriptionId:
    11. VendorOrderId: Required When the status is 1 otherwise AppXite won’t be able to Map the order with the vendor’s side.
    12. VendorSubscriptionId: Required When the status is 1 otherwise AppXite won’t be able to Map the subscription with the vendor’s side.
    13. RequestedByUserId: ¦OrderItem.CreatedById§

Params Model:

  1. {
  2.   "SubscriptionStartDate": "",
  3.   "SubscriptionEndDate": "",
  4.   "OrderId": "12388b9a-8bb0-44c5-bb8d-7527315a13d8",
  5.   "ProvisionStatus": "0",
  6.   "AssociatedPartnerId": "",
  7.   "LineItemNumber": "0",
  8.   "OfferId": "VendorOfferId",
  9.   "VendorId": "af817907-beb0-4ce2-be96-b674de7a876b",
  10.   "VendorResellerId": "B5611D86-1587-47CF-9B52-0781CD32113A",
  11.   "VendorCustomerId": "bfd9af12-5576-4fe6-bb41-051a9b8533ec",
  12.   "FriendlyName": "Offer Name – not Required",
  13.   "Quantity": "",
  14.   "BundleId": "",
  15.   "ParentSubscriptionLine": "",
  16.   "ParentSubscriptionId": "",
  17.   "VendorSubscriptionId": "",
  18.   "SubscriptionId": "",
  19.   "OrderItemId": "2fa698d5-6c0b-4b32-85d6-123776a314a4",
  20.   "VendorOrderId": "e4e39800b20e",
  21.   "ErrorMessage": "",
  22.   "RequestedByUserId": "ee78d804-cecf-47c9-a77a-ff6c4c5d5200",
  23.   "RequestedCulture": "",
  24.   "Operation": "CancelOrder",
  25.   "ApplicationId": ""
  26. }

Upload your sequences

You can add and update integration sequences in “My products” on your platform.

To save sequences for a specific offer:

  1. Find the offer and click "Edit":
    Picture2.png
  2. Scroll down and select “Custom” in the “Provisioning” section:Picture1.png
  3. Copy your sequences from a JSON file into the text field or upload the file itself.
  4. Save your changes on the page.

To save default sequences that apply to all offers that don't have their own:

  1. Click "Edit" on your vendor organization:
    Picture4.png
  2. Scroll down and select "Custom" in the “Provisioning” section:
    Picture6.png
  3. Save your changes on the page.

As soon as you save the changes, the uploaded sequences will be used for all operations defined in the them, such as “PlaceOrder”, “ChangeOrder”, “Schedule”, “CancelOrder” etc.

Verify your integration

  1. Is the integration ready when I save it?

    Once the sequences have been uploaded, you will be able to try the operations added. For example, we have uploaded sequences for both PostOrder and ChangeOrder. We can run the corresponding Operation from AppXite’s platform to verify that the sequences are uploaded. So, we try to provision an offer and check if the actions were performed, like checking the vendor’s portal if the order has been created or changed. Checking logs is not yet available.

  2. Does the offer need to be published before I add sequences?

    You should add the sequences for your offer before you publish it to guarantee that all orders that users with access to the offer might place work. You may update your sequences at any time without having to unpublish the offer first, as such changes apply instantly.

  3. How do I test the integration?

    It’s easier to create and troubleshoot sequences if you understand which customer actions trigger their respective operations in the sequence. Here they are:

Platform’s Operation

Sequences Operation

Comments

Purchase an Offer

PostOrder

 

Change a Subscription

ChangeOrder

 

 

Schedule

Process In-Progress orders, this is a job that runs each 20 mins to try to complete the InProgress Orders

Schedule Changes on Renewal Date

ScheduleOrder

 

Cancel an Order

CancelOrder

 

 

  1. How do I know that the works?

    To test your sequences, you must test the integration context that covers your implementation. For example, if the Sequences that I’ve uploaded has both provisioning and changing subscription, so I will go to AppXite and perform both operations, provisioning an order and changing the configuration of the subscription. As a result, we must have 2 orders with status finished on the order page, a new subscription must be created on the subscription page, and you can check the vendor’s portal to check if the called endpoint has done what was intended to.

  2. How do I troubleshoot and test again?

    If you encounter issues such as order failing, check the sequences related to the corresponding failing operation and try again.

Was this article helpful?

0 out of 0 found this helpful

Add comment

Please sign in to leave a comment.