App Center Integration – Asynchronous Events

Asynchronous events

All subscription events that involve a response can also be supported as asynchronous (delayed response) events. (SUBSCRIPTION_NOTICE is the only subscription event that does not involve a response and therefore is only supported as a synchronous event.)

When App Center calls an Partner with a notification URL, they return a JSON or XML response, as well as an HTTP response code. Usually, this code is 200 (OK) or 201 (Created). Additionally, however, App Center will recognize an code of 202 (Accepted) as a mechanism for the Partner to tell App Center that the event has been received and is being processed, and the Partner will notify App Center upon completion. The Partner can make an HTTP POST to the /api/integration/v1/events/{eventUrl}/result endpoint to notify App Center of the result. The POST body is the same as it would be for a synchronous event response. The subscription or assignment will remain in a “pending” state (e.g., PENDING_USER_ACTIVATION, PENDING_REMOTE_CREATION, or PENDING_REMOTE_CANCELLATION) in the App Center marketplace until App Center is notified of the result. When a subscription or assignment is in the pending state, the user cannot act upon it.

Asynchronous event notification flow

All asynchronous event notifications follow the same general flow:

  1. An event is triggered by a customer action (e.g., purchasing an application, upgrading an existing subscription, cancelling a subscription, or failing to pay an invoice).
  2. App Center sends an asynchronous event notification to the application vendor (Partner). This event is uniquely identified by an event URL. More details about the notification URL are provided below.
  3. The Partner must validate the OAuth-signature on the request, then can read the event URL from the parameters to send an HTTP GET request for more information about the particular subscription event.
  4. App Center sends a JSON or XML response to the Partner.
  5. The Partner then does a POST request back to App Center, passing account and/or status information. This status information is used by App Center to provide feedback to the customer via the App Center UI.
  6. The key difference with an asynchronous event is that the header returns a 202 (Accepted) HTTP code. App Center will recognize this code as a pending event.
  7. Once the event is manually resolved (such as an account is provisioned), the Partner can POST a result to the eventUrl.

Example asynchronous event notification flow

An example of a asynchronous event notification flow is shown below using a create subscription.

User Bob purchases application Gizmo123. This creates an asynchronous SUBSCRIPTION_ORDER event identified by URL https://www.sapappcenter.com/api/integration/v1/events/12345.

App Center calls http://example.com/create?url=https%3A%2F%2Fwww.sapappcenter.com%2Fapi%2Fintegration%2Fv1%2Fevents%2F12345
Example.com issues a signed fetch to: https://www.sapappcenter.com/api/integration/v1/events/12345

App Center sends a JSON or XML response to the Partner.

JSON

{
    "type": "SUBSCRIPTION_ORDER",
    "marketplace": {
      "baseUrl": "https://www.sapappcenter.com",
      "partner": "Partner Name"
    },
    "creator": {
      "address": {
        "city": "Cambridge",
        "country": "US",
        "phone": "8582312882",
        "state": "MA",
        "street1": "123 Main St",
        "zip": "02142"
      },
      "email": "testuser@testco.com",
      "firstName": "Test",
      "language": "en",
      "lastName": "User",
      "locale": "en-US",
      "openId": "https://www.sapappcenter.com/openid/id/5d1f6f79-efff-411e-abe5-0b0a01610f04",
      "uuid": "5d1f6f79-efff-411e-abe6-0b0a01610f04"
    },
    "payload": {
      "company": {
        "country": "US",
        "name": "Test User",
        "phoneNumber": "8582312882",
        "uuid": "dc61a736-55b6-40fc-9b5a-6b17cbe6eb62"
      },
      "order": {
        "editionCode": "0D5C06DB-FFEC-43a1-A6AF-EFB7E9B17905",
        "pricingDuration": "MONTHLY",
        "items": [{
          "quantity": "3",
          "unit": "USER"
        }]
      }
    }
}

XML

<?xml version="1.0" encoding="UTF-8" ?>
<event>
        <type>SUBSCRIPTION_ORDER</type>
        <marketplace>
                <baseUrl>https://www.sapappcenter.com</baseUrl>
                <partner>Partner Name</partner>
        </marketplace>
        <creator>
                <address>
                        <city>Cambridge</city>
                        <country>US</country>
                        <phone>8582312882</phone>
                        <state>MA</state>
                        <street1>123 Main St</street1>
                        <zip>02142</zip>
                </address>
                <email>testuser@testco.com</email>
                <firstName>Test</firstName>
                <language>en</language>
                <lastName>User</lastName>
                <locale>en-US</locale>
                <openId>https://www.sapappcenter.com/openid/id/5d1f6f79-efff-411e-abe5-0b0a01610f04</openId>
                <uuid>5d1f6f79-efff-411e-abe6-0b0a01610f04</uuid>
        </creator>
        <payload>
                <company>
                        <country>US</country>
                        <name>Test User</name>
                        <phoneNumber>8582312882</phoneNumber>
                        <uuid>dc61a736-55b6-40fc-9b5a-6b17cbe6eb62</uuid>
                </company>
                <order>
                        <editionCode>0D5C06DB-FFEC-43a1-A6AF-EFB7E9B17905</editionCode>
                        <pricingDuration>MONTHLY</pricingDuration>
                        <items>
                                <quantity>3</quantity>
                                <unit>USER</unit>
                        </items>
                </order>
        </payload>
</event>

Example.com starts the creation a new account for Bob in its account system.

Example.com returns a JSON or XML response to the original HTTP request.

JSON

Status Code: 202 Accepted
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 17
Content-Type: application/json;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
{
    "success":true
}

XML

Status Code: 202 Accepted
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 35
Content-Type: application/xml;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
<result>
    <success>true</success>
</result>

App Center puts the subscription into the PENDING_REMOTE_CREATION state. The user cannot do anything with the subscription at this time.

The Partner sends an HTTP POST to https://www.sapappcenter.com/api/integration/v1/events/12345/result to indicate the account creation is complete. Note that the POST body is the same object as a synchronous event response.

JSON

Status Code: 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 28
Content-Type: application/json;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
{
    "accountIdentifier":"789xyz",
    "success":true
}

XML

Status Code: 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 47
Content-Type: application/xml;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
<result>
    <accountIdentifier>789xyz</success>
    <success>true</success>
</result>

Or in the event of an error, Example.com can return an error code.

JSON

Status Code: 409 Conflict
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 46
Content-Type: application/json;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
{
    "success": "false"
    "errorCode": "USER_ALREADY_EXISTS"
    "message": "Optional message about the user already existing on Partner"
}

XML

Status Code: 409 Conflict
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 62
Content-Type: application/xml;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
<result>
    <success>false</success>
    <errorCode>USER_ALREADY_EXISTS</errorCode>
    <message>Optional message about the user already existing on Partner</message>
</result>

SAP App Center Integration – Getting Started Guide

Please feel free to continue reading but please keep in mind that the first step to engage the App Center team (if you haven’t already) is to fill out the Integration Scoping and Design document.

Are you tenanting on SAP Cloud platform (Neo)? Check out this SAP CP specific deployment guide

Subscription Lifecycle

The SAP App Center manages the lifecycle of subscriptions to products purchase through the marketplace. A subscription can be in one the following states:

  • FREE_TRIAL: the subscription is in free trial, the customer is not being charged.
  • FREE_TRIAL_EXPIRED: the free trial has expired, the customer cannot use his subscription unless he converts to a paid subscription.
  • ACTIVE: regular subscription in “good standing”. If the application is not free, the customer is being charged the appropriate amount.
  • SUSPENDED: an invoice for this subscription is overdue. The subscription cannot be used unless the customers pays the invoice.
  • CANCELLED: the subscription is not active anymore and does not show up in the customer marketplace account.

Event Flow

The first step to integrating with the SAP App Center is to understand each of these states, and how your event listener/app service will respond to each inbound request, so please read and consider carefully.

Subscribing to a product

The entry state for a subscription can either be FREE_TRIAL (if the edition purchased by the user has a free trial period) or ACTIVE. When a user purchases a subscription to a product, the App Center powered marketplace will notify the Partner by triggering a SUBSCRIPTION_ORDER event.

Free trial support

A subscription in the FREE_TRIAL state will move to the FREE_TRIAL_EXPIRED state once the free trial expires and if the user doesn’t convert to a paid subscription. In this case, the marketplace will notify the Partner by triggering a SUBSCRIPTION_NOTICE event, with a notice type DEACTIVATED and containing the new subscription state.

On the other hand, if a customer decides to convert a free trial subscription to a paid one (before or after the free trial expires), the subscription state will change to ACTIVE and the marketplace will notify the Partner by triggering a SUBSCRIPTION_NOTICE event, with a notice type REACTIVATED and containing the new subscription state.

Delinquent subscriptions

By default, App Center will consider a subscription to be delinquent when 3 payments have been missed.

When a customer misses the payment of an invoice for a subscription in the ACTIVE state, the subscription state changes to SUSPENDED and the marketplace will notify the Partner by triggering a SUBSCRIPTION_NOTICE event, with a notice type DEACTIVATED and containing the new subscription state.

When the customer pays the overdue invoice, the subscription state changes back to ACTIVE and the marketplace will notify the Partner by triggering a SUBSCRIPTION_NOTICE event, with a notice type REACTIVATED and containing the new subscription state.

When the customer fails to pay the overdue invoice, the customer’s subscription in the App Center marketplace may be closed, triggering a CLOSED notice type. The Partner should not delete a delinquent subscription unless notified by App Center that a subscription has been closed.

Modifying a subscription

A customer can modify the items ordered for subscriptions to products including metered items (where the customer has to choose the number of seats purchased, or some other items at purchase time). In this case the marketplace will notify the Partner by triggering a SUBSCRIPTION_CHANGE event, containing an updated list of the new ordered items.

Subscription end of life

A subscription can come to its end of life, which is the CANCELLED state one of two ways: the customer decides to end his subscription by going to his marketplace account and cancelling it. In this case, the marketplace will notify the Partner by triggering a SUBSCRIPTION_CANCEL event, after which he subscription is cleared from the customer account and the charges are stopped; or the subscription has been in a delinquent state (FREE_TRIAL_EXPIRED or SUSPENDED) for period of time exceeding the marketplace grace period (typically 2 or 3 months). In this case, the marketplace will notify the Partner by triggering a SUBSCRIPTION_NOTICE event, with a notice type CLOSED, after which he subscription is cleared from the customer account and the charges are stopped.

Subscription Event Flow

All subscription event notifications follow the same general flow:

Workflow

  1. An event is triggered by a customer action (e.g., purchasing an application, upgrading an existing subscription, cancelling a subscription, or failing to pay an invoice).
  2. App Center sends a subscription event notification to the application vendor (Partner). This event is uniquely identified by an event URL. More details about the notification URL are provided below.
  3. The Partner must validate the OAuth-signature on the request, then can read the event URL from the parameters to send an HTTP GET request for more information about the particular subscription event.
  4. App Center sends a JSON or XML response to the Partner.
  5. The Partner then POSTs a request back to App Center, passing account and/or status information.
  6. This status information is used by App Center to provide feedback to the customer via the App Center UI.

Synchronous and asynchronous events

Typically when App Center sends a notification to an Partner, a response is expected. Subscription events are assumed to be synchronous (the response is received immediately) unless otherwise stated. However, when a business process requires a delayed response, App Center can support it with an asynchronous event. For asynchronous events, App Center listens for the delayed response to arrive.

The SUBSCRIPTION_NOTICE event is the only subscription event that does not involve a response so it is only supported as a synchronous event.

Notification URLs and responses

When a user triggers an event on an App Center-powered marketplace, the marketplace performs an HTTP GET, signed with your OAuth credentials, to your notification URL and passes the event URL as a parameter. You must verify the OAuth signature for the call made to your notification URL is valid and refuse the call by returning an HTTP status 401 or 403 if it is not valid. Once the call has been validated, you can perform an HTTP GET, signed with your OAuth credentials, to the event URL you received to retrieve the information about this event in JSON or XML form. You can then process the event on your side (account creation, account updates, account cancellations, etc.). After processing the event you must respond to the call you received in JSON or XML form indicating the result of the operation. If an error occurred while processing the event, do not return a 500 or 404 status. Always return a 200 status with properly formatted JSON or XML as described below.

Success response to a notification

JSON

{
  "success": "true",
  "accountIdentifier": "new-account-identifier"
}

XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<result>
<success>true</success>
<accountidentifier>new-account-identifier</accountidentifier>
<result>

App Center only requires an accountIdentifier in the response to a Subscription Order Event so we can know how to reference the new customer account in future Event Notifications.

Error response to a notification

JSON

{
"success": "false",
"errorCode": "ACCOUNT_NOT_FOUND",
"message": "The account TEST123 could not be found."
}

XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<result>
 <success>false</success>
 <errorcode>ACCOUNT_NOT_FOUND</errorcode>
 <message>The account TEST123 could not be found.</message>
<result>

Event flags

Event notifications may contain an event flag field of the form value. App Center supports two possible flag values:

  • DEVELOPMENT: This event was generated for an application that is still in development. This is intended to allow application developers to identify events generated by applications in development that are not publicly visible. For example, it may be used to distinguish debugging and developer accounts from live accounts. These events need to be honored, but will not generate invoices or payments.
  • STATELESS: This event is for testing purposes only. No persistent state change is needed by the application. Applications will be expected to return some well-formed response, such as an error code. This flag will be used for API uptime monitoring.

Example subscription event notification flow

An example of a subscription event notification flow is shown below using a create subscription.

User Bob purchases application Gizmo123. This creates a SUBSCRIPTION_ORDER event identified by URL https://www.sapappcenter.com/api/integration/v1/events/12345.
AppCenter calls http://example.com/create?url=https%3A%2F%2Fwww.sapappcenter.com%2Fapi%2Fintegration%2Fv1%2Fevents%2F12345.
Example.com issues a signed fetch to: https://www.sapappcenter.com/api/integration/v1/events/12345
AppCenter returns a subscription order event.

JSON

{
    "type": "SUBSCRIPTION_ORDER",
    "marketplace": {
      "baseUrl": "https://www.sapappcenter.com",
      "partner": "SAMPLEPARTNER"
    },
    "creator": {
      "address": {
        "firstName": "Sample",
        "fullName": "Sample Tester",
        "lastName": "Tester"
      },
      "email": "sampletester@testco.com",
      "firstName": "Sample",
      "language": "en",
      "lastName": "Tester",
      "locale": "en-US",
      "openId": "https://www.sapappcenter.com/openid/id/211aa367-f53b-4606-8887-80a381e0ef69",
      "uuid": "211aa369-f53b-4606-8887-80a361e0ef66"
    },
    "payload": {
      "company": {
        "country": "US",
        "name": "Sample Testing co.",
        "uuid": "bd58b532-323b-4627-a828-57729489b27b",
        "website": "www.testerco.com"
      },
      "order": {
        "editionCode": "FREE",
        "pricingDuration": "MONTHLY"
      }
    }
}

XML

  <?xml version="1.0" encoding="UTF-8" ?>
    <event>
        <type>SUBSCRIPTION_ORDER</type>
        <marketplace>
            <baseUrl>https://www.sapappcenter.com<baseUrl>
            <partner>SAMPLEPARTNER</partner>
        </marketplace>
        <creator>
            <address>
                <firstName>Sample</firstName>
                <fullName>Sample Tester</fullName>
                <lastName>Tester</lastName>
            </address>
            <email>sampletester@testco.com</email>
            <firstName>Sample</firstName>
            <language>en</language>
            <lastName>Tester</lastName>
                        <locale>en-US</locale>
            <openId>https://www.sapappcenter.com/openid/id/211aa367-f53b-4606-8887-80a381e0ef69</openId>
            <uuid>211aa369-f53b-4606-8887-80a361e0ef66</uuid>
        </creator>
        <payload>
            <company>
                <country>US</country>
                <name>Sample Testing co.</name>
                <uuid>bd58b532-323b-4627-a828-57729489b27b</uuid>
                <website>www.testerco.com</website>
            </company>
            <order>
                <editionCode>FREE</editionCode>
                <pricingDuration>MONTHLY</pricingDuration>
            </order>
        </payload>
    </event>

Example.com creates a new account for Bob in its account system.
Example.com returns a JSON or XML response to the original HTTP request.

JSON

Status Code: 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 28
Content-Type: application/json;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff

{
"accountIdentifier":"789xyz",
"success":true
}

XML

Status Code: 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 47
Content-Type: application/xml;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
<result>
    <accountIdentifier>789xyz</success>
    <success>true</success>
</result>

Or in the event of an error, Example.com can return an error code.

JSON

Status Code: 409 Conflict
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 46
Content-Type: application/json;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
{
"success": "false"
"errorCode": "USER_ALREADY_EXISTS"
"message": "Optional message about the user already existing on Partner"
}

XML

Status Code: 409 Conflict
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 62
Content-Type: application/xml;charset=UTF-8
Date: Tue, 25 Aug 2015 20:40:25 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E93047B4DE01A6D3447EACEDD462CA8A; Path=/; HttpOnly
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
<result>
    <success>false</success>
    <errorCode>USER_ALREADY_EXISTS</errorCode>
    <message>Optional message about the user already existing on ISV</message>
</result>

Create subscription

Customers can purchase products (create a subscription) through the marketplace. These subscriptions can be either FREE_TRIAL (if the edition purchased by the user has a free trial period) or ACTIVE. Subscriptions can be created either through the App Center UI (shown below) or by calling the App Center subscription API.

The create subscription event notification allows you to receive notice (SUBSCRIPTION_ORDER) when a customer purchases a subscription. Only items which are adjustable by the end user (when purchasing or updating an edition) are included in a create subscription event. Metered billing usage and “included items” are handled separately. In order to allow users to purchase your product, you must define a subcription create notification URL, such as https://example.com/create?eventUrl={eventUrl}, on the product’s “Edit Integration” page. App Center will call this URL when users purchase new subscriptions.

The general flow for a create subscription event notification is as follows:

  1. A user orders an application from App Center.
  2. App Center creates a uniquely identified SUBSCRIPTION_ORDER event, which is persisted in the App Center. This event is uniquely identified by an event URL, such as https://www.sapappcenter.com/api/integration/v1/events/d15bb36e-5fb5-11e0-8c3c-00262d2cda03.
  3. App Center calls the configured subscription order notification URL, passing the event URL as a parameter.
  4. The application vendor must first validate the OAuth-signature on the request.
  5. The application vendor can then get the event URL from the URL parameters and read information regarding the SUBSCRIPTION_ORDER event that was triggered. Briefly, this event contains the following elements:
    • type: The type of the event (SUBSCRIPTION_ORDER in this case).
    • marketplace: Information about the App Center-powered marketplace on which the event took place.
    • creator: The identity of the user who triggered the event.
    • payload: The event payload, containing the following elements:
      • order: The order information, which contains an edition code, the quantity of units bought, and the unit type such as “users” associated with the order.
      • company: The company creating the order. Contact information about the ordering company is provided if it is available, but may be empty.
  6. The application vendor creates the account and returns a result JSON or XML with these elements:
    • success: Which should be “true” or “false.”
    • accountIdentifier: A sequence of characters that will be use to identify the account. This identifier will be used in subsequent transactions to identify this account and cannot be changed.
    • errorCode: If “success” is false, this should contain one of the supported error codes.
    • message: An optional message containing information about the result of the operation.

Example SUBSCRIPTION_ORDER event notification

JSON

{
    "type": "SUBSCRIPTION_ORDER",
    "marketplace": {
      "baseUrl": "https://www.sapappcenter.com",
      "partner": "SAMPLEPARTNER"
    },
    "creator": {
      "address": {
        "firstName": "Test",
        "fullName": "Test User",
        "lastName": "User"
      },
      "email": "testuser@testco.com",
      "firstName": "Test",
      "language": "en",
      "lastName": " User",
      "locale": "en-US",
      "openId": "https://www.sapappcenter.com/openid/id/47cb8f55-1af6-5bfc-9a7d-8061d3aa0c97",
      "uuid": "47cb8f55-1af6-5bfc-9a7d-8061d3aa0c97"
    },
    "payload": {
      "company": {
        "country": "US",
        "name": "tester",
        "phoneNumber": "1-800-333-3333",
        "uuid": "385beb51-51ae-4ffe-8c05-3f35a9f99825",
        "website": "www.testco.com"
      },
      "order": {
        "editionCode": "Standard",
        "pricingDuration": "MONTHLY",
        "items": [{
          "quantity": "4",
          "unit": "USER"
        }]
      }
    }
}

XML

<?xml version="1.0" encoding="UTF-8" ?>
<event>
    <type>SUBSCRIPTION_ORDER</type>
    <marketplace>
        <baseUrl>https://www.sapappcenter.com</baseUrl>
        <partner>SAMPLEPARTNER</partner>
    </marketplace>
    <creator>
        <address>
            <firstName>Test</firstName>
            <fullName>Test User</fullName>
            <lastName>User</lastName>
        </address>
        <email>testuser@testco.com</email>
        <firstName>Test</firstName>>
        <language>en</language>
        <lastName>User</lastName>
                <locale>en-US</locale>
        <openId>https://www.sapappcenter.com/openid/id/47cb8f55-1af6-5bfc-9a7d-8061d3aa0c97</openId>
        <uuid>47cb8f55-1af6-5bfc-9a7d-8061d3aa0c97</uuid>
    </creator>
    <payload>
        <company>
            <country>US</country>
            <name>tester</name>
            <phoneNumber>1-800-333-3333</phoneNumber>
            <uuid>385beb51-51ae-4ffe-8c05-3f35a9f99825</uuid>
            <website>www.testco.com</website>
        </company>
        <order>
            <editionCode>Standard</editionCode>
            <pricingDuration>MONTHLY</pricingDuration>
            <items>
                <quantity>4</quantity>
                <unit>USER</unit>
            </items>
        <order>
    </payload>
</event>

Change subscription

Existing subscriptions can be updated either through the App Center UI or by calling the App Center subscription API.

The change subscription event notification allows you to receive notice (SUBSCRIPTION_CHANGE) when an existing subscription is changed in some way (e.g,. upgrade or downgrade). A SUBSCRIPTION_CHANGE is triggered whenever an admin within the App Center platform modifies the current subscription, which would be represented by a change to the plan values or plan ID. It can also be triggered by the admin transferring the owner of the subscription, which would be represented with new creator values. Only items which are adjustable by the end user (when purchasing or updating an edition) are included in a change subscription event. Metered billing usage and “included items” are handled separately. In order to allow users to make changes to subscriptions, you must configure a Subscription Change Notification URL, such as https://example.com/change?eventUrl={eventUrl}, in the product Edit Integration page.

The general flow for a change subscription event notification is as follows:

  1. A user changes (upgrades or downgrades) a subscription from App Center.
  2. App Center creates a uniquely identified SUBSCRIPTION_CHANGE event, which is persisted in the App Center-powered marketplace. This event is uniquely identified by an event URL, such as https://www.sapappcenter.com/api/integration/v1/events/d15bb36e-5fb5-11e0-8c3c-00262d2cda03.
  3. App Center calls the configured subscription change notification URL, passing the event URL as a parameter.
  4. The application vendor must first validate the OAuth-signature on the request.
  5. The application vendor can then get the event URL from the URL parameters and read information regarding the SUBSCRIPTION_CHANGE that was triggered. Briefly, this event contains the following elements:
    • type: The type of the event (SUBSCRIPTION_CHANGE in this case)
    • marketplace: Information about the App Center-powered marketplace on which the event took place.
    • creator: The identity of the admin creating the event.
    • payload: The event payload, containing the following elements:
      • order: The order change information.
      • account: The account identifier provided by the Application Vendor in the initial Subscription Order Event.
  6. The application vendor returns a result JSON or XML with these elements:
    • success: Which should be “true” or “false.”
    • errorCode: If “success” is false, this should contain one of the supported error codes.
    • message: An optional message containing information about the result of the operation.

Example SUBSCRIPTION_CHANGE event notification.

JSON

{
    "type": "SUBSCRIPTION_CHANGE",
    "marketplace": {
      "baseUrl": "https://www.sapappcenter.com",
      "partner": "SAMPLEPARTNER"
    },
    "creator": {
      "address": {
        "city": "San Jose",
        "country": "US",
        "firstName": "Test",
        "fullName": "Test User",
        "lastName": "User",
        "state": "CA",
        "street1": "1 Main St",
        "zip": "95131"
      },
      "email": "testuser@testco.com",
      "firstName": "Test",
      "language": "en",
      "lastName": "User",
      "locale": "en-US",
      "openId": "https://www.sapappcenter.com/openid/id/7f59aad1-85cd-4c04-b35b-906ee53acc71",
      "uuid": "7f59aad1-85cd-4c04-b35b-906ee53acc71"
    },
    "payload": {
      "account": {
        "accountIdentifier": "206123",
        "status": "ACTIVE"
      },
      "order": {
        "editionCode": "DME",
        "pricingDuration": "DAILY",
        "items": [{
          "quantity": "0",
          "unit": "GIGABYTE"
        }]
      }
    }
}

XML

<?xml version="1.0" encoding="UTF-8" ?>
<event>
    <type>SUBSCRIPTION_CHANGE</type>
    <marketplace>
        <baseUrl>https://www.sapappcenter.com</baseUrl>
        <partner>SAMPLEPARTNER</partner>
    </marketplace>
    <creator>
        <address>
            <city>San Jose</city>
                       <country>US</country>
                       <firstName>Test</firstName>
            <fullName>Test User</fullName>
            <lastName>User</lastName>
                       <state>CA</state>
                       <street1>1 Main St</street1>
                       <zip>95131</zip>
               </address>
        <email>testuser@testco.com</email>
        <firstName>Test</firstName>>
               <lastName>User</lastName>
               <locale>en-US</locale>
        <openId>https://www.sapappcenter.com/openid/id/47cb8f55-1af6-5bfc-9a7d-               8061d3aa0c97</openId>
        <uuid>47cb8f55-1af6-5bfc-9a7d-8061d3aa0c97</uuid>
       </creator>
    <payload>
               <account>
                       <accountIdentifier>206123</accountIdentifier>
                       <status>ACTIVE</status>
               </account>
        <order>
            <editionCode>DME</editionCode>
            <pricingDuration>DAILY</pricingDuration>
            <items>
                <quantity>0</quantity>
                <unit>GIGABYTE</unit>
            </items>
        <order>
    </payload>
</event>

Cancel subscription

Existing subscriptions can be canceled either through the App Center UI or by calling the App Center subscription API.

The cancel subscription event notification allows you to receive notice (SUBSCRIPTION_CANCEL) when the customer cancels an existing subscription. In order to allow users to cancel their subscription to your product, you must define a subcription cancel notification URL, such as https://example.com/cancel?eventUrl={eventUrl}, on the product’s “Edit Integration” page.

If App Center does not receive a successful response from the Partner to a SUBSCRIPTION_CANCEL event, the cancellation process is aborted, and the subscription stays in its current state. The customer is notified of the failure and presented with the error message returned by the Partner (if any).

The general flow for a cancel subscription event notification is as follows:

  1. A user cancels a subscription from App Center.
  2. App Center creates a SUBSCRIPTION_CANCEL event identified by a corresponding token value.
  3. App Center calls the Subscription Cancel Notification URL.
  4. The application vendor must validate App Center’s OAuth-signature.
  5. The application vendor issues an OAuth-signed fetch to read the SUBSCRIPTION_CANCEL Event information using the token value. See the Event API documentation for details. Briefly, this subscription cancel event contains:
    • type: The type of the event (SUBSCRIPTION_CANCEL in this case)
    • marketplace: Information about the App Center-powered marketplace on which the event took place.
    • creator: The identity of the admin creating the event.
    • payload: The event payload, containing the following elements:
      • account: The account identifier provided by the Application Vendor in the initial Subscription Order Event.
  6. The application vendor returns a result JSON or XML with these parameters:
    • success: Which should be “true” or “false.”
    • errorCode: If “success” is false, this should contain one of the supported error codes.
    • message: An optional message containing information about the result of the operation.

Example SUBSCRIPTION_CANCEL event notification

JSON

{
    "type": "SUBSCRIPTION_CANCEL",
    "marketplace": {
      "baseUrl": "https://www.sapappcenter.com",
      "partner": "SAMPLEPARTNER"
    },
    "creator": {
      "address": {
        "city": "Sommerville",
        "country": "US",
        "firstName": "Test",
        "fullName": "Test User",
        "lastName": "User",
        "phone": "5305556465",
        "state": "MA",
        "street1": "55 Grove St",
        "zip": "02144"
      },
      "email": "testuser@testco.com",
      "firstName": "Test",
      "language": "en",
      "lastName": "User",
      "locale": "en-US",
      "openId": "https://www.sapappcenter.com/openid/id/d124bf8b-0b0b-40d3-831b-b7f5a514d487",
      "uuid": "d124bf8b-0b0b-40d3-831b-b7f5a514d487"
    },
    "payload": {
      "account": {
        "accountIdentifier": "9d6fca98-aa94-462b-85fa-118804ad3fe3",
        "status": "ACTIVE"
      }
    }
}

XML

<event>
    <type>SUBSCRIPTION_CANCEL</type>
    <marketplace>
        <baseUrl>https://www.sapappcenter.com</baseUrl>
        <partner>SAMPLEPARTNER</partner>>
    </marketplace>
    <creator>
        <address>
            <city>Sommerville</city>
            <country>US</country>
            <firstName>Test</firstName>
            <fullName>Test User</fullName>
            <lastName>User</lastName>
            <phone>5305556465</phone>
            <state>MA</state>
            <street1>55 Grove St</street1>
            <zip>02144</zip>
        </address>
        <email>testuser@testco.com</email>
        <firstName>Test</firstName>
        <language>en</language>
        <lastName>User</lastName>
                <locale>en-US</locale>
        <openId>https://www.sapappcenter.com/openid/id/d124bf8b-0b0b-40d3-831b-b7f5a514d487</openId>
        <uuid>d124bf8b-0b0b-40d3-831b-b7f5a514d487</uuid>
    </creator>
    <payload>
        <account>
            <accountIdentifier>9d6fca98-aa94-462b-85fa-118804ad3fe3</accountIdentifier>
            <status>ACTIVE</status>
        </account>
    </payload>
</event>

Subscription notice

The subscription notice event notification allows you to receive overdue or deliquent notices on an existing subscription, as well as to receive notice (SUBSCRIPTION_NOTICE) when the overdue invoice has been resolved. In order to support these subscription notices, you must define a subcription notice notification URL on the product’s “Edit Integration” page.

The general flow for a subscription notice event notification is as follows:

  1. A subscription’s status changes, such as going overdue or delinquent, on App Center.
  2. App Center creates a SUBSCRIPTION_NOTICE event identified by an event URL.
  3. App Center performs a GET operation on the URL defined as the Subscription Notice listener URL, passing the event URL identifying this event.
  4. The application vendor issues an OAuth-signed fetch to read the SUBSCRIPTION_NOTICE Event information using the token value. See the Event API documentation for details. Briefly, this Subscription Notice Event contains:
    • type: The type of the event (SUBSCRIPTION_NOTICE in this case)
    • marketplace: Information about the App Center-powered marketplace on which the event took place.
    • payload: The event payload, containing the following elements:
      • notice: A type element whose value can be either DEACTIVATED, REACTIVATED, CLOSED or UPCOMING_INVOICE.
      • account: The account identifier provided by the application in the initial Subscription Order Event and its current status (FREE_TRIAL, SUSPENDED, etc.).
  5. The application vendor returns a result JSON or XML with these parameters:
    • success: Which should be “true” or “false.”
    • errorCode: If “success” is false, this should contain one of the supported error codes.
    • message: An optional message containing information about the result of the operation.

Example SUBSCRIPTION_NOTICE event notification.

JSON

{
"type": "SUBSCRIPTION_NOTICE",
"marketplace": {
"baseUrl": "https://www.sapappcenter.com",
"partner": "App Center"
},
"payload": {
"account": {
"accountIdentifier": "a3f72246-5377-4d92-8bdc-b1b6b450c55c",
"status": "ACTIVE"
},
"notice": { "type": "UPCOMING_INVOICE" }
}
}

XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<event>
    <type>SUBSCRIPTION_NOTICE</type>
    <marketplace>
        <baseurl>https://www.sapappcenter.com</baseurl>
        <partner>SAMPLEPARTNER</partner>
    </marketplace>
        <payload>
        <account>
            <accountidentifier>a3f72246-5377-4d92-8bdc-b1b6b450c55c</accountidentifier>
            <status>ACTIVE</status>
        </account>
        <configuration/>
        <notice>
            <type>UPCOMING_INVOICE</type>
        </notice>
    </payload>
</event>

Notice types

  1. DEACTIVATED – Means the account has been deactivated and is in a SUSPENDED or FREE_TRIAL_EXPIRED state. It is recommended that all access to the Partner’s application be suspended (but not deleted). Account deactivation may occur if, for example, the account holder is overdue in making a payment or if abuse is detected.

  2. REACTIVATED – Means an account should be considered active (ACTIVE or FREE_TRIAL state) and receive its typical access. This status will usually indicate that the account holder has paid an overdue invoice.

  3. CLOSED – Means that the account is in a CANCELLED, and that it should be deleted by the Partner. In most cases, this event should trigger the same code on the Partner as the SUBSCRIPTION_CANCELLED event.

  4. UPCOMING_INVOICE – Informs a vendor that there is an upcoming invoice that will be computed for this account, before it is generated. This notice is issued 21 hours prior to the start of the invoice run that will include the vendor’s invoice. (If an invoice is queued and generated, for example, four hours after the invoice generation run starts, the upcoming invoice notice is issued 25 hours before invoice generation.) The intention of this notice is to give a vendor the opportunity to update the App Center with any usage information via the Billing Usage API, which will be included on the upcoming invoice.

Error handling

Since the DEACTIVATED, REACTIVATED and CLOSED notices reflect state changes in the subscription lifecycle, it is important for Partners to process these events successfully. To mitigate temporary errors (downtimes, transport errors, etc.), the App Center marketplace will attempt to redeliver the notice up to 10 times, following an exponential backoff algorithm: the first redelivery will be attempted 30 minutes after the last failure, then 1 hour after the last failure, then 2 hours, etc. to a minimum of once a day. The redelivery will happen in a 1 hour window following the indicated time (so the first redelivery can happen anytime from 30 minutes to 1 hour 30 minutes after the initial failure).

If the marketplace does not receive a successful response from the Partner to a SUBSCRIPTION_NOTICE event, the behavior is as follows:

for UPCOMING_INVOICE notices, the invoice is still sent out to the customer. The Partner will be notified again when the next invoice is about to be created.
for DEACTIVATED, REACTIVATED and CLOSED notices, the marketplace will attempt to redeliver the notice up to 10 times according to an exponential backoff algorithm. The redelivery attempt will occur 30min, 1h, 2h, 4h, etc. up to a day after the time of last failure to deliver.