Data Plan Agent API

Motivation

As mentioned in the overview, depending on the use cases that the operator wishes to support, the DPA has to implement a combination of Google Mobile Data Plan Sharing API and the Data Plan Agent API. This document describes the Data Plan Agent API that Google will use to identify the user's mobile data plans, retrieve information about these plans, and purchase data plans.

Authentication

Before GTAF can call, the DPA must authenticate GTAF. As part of operator onboarding process, we will check the validity of DPA SSL certificate. We currently REQUIRE the use of OAuth2 for mutual authentication.

API Description

GTAF uses user key, which identifies a subscriber to the operator, when querying the operator's DPA. When GTAF is querying the DPA on behalf of applications that have access to the MSISDN, GTAF MAY use MSISDN. At a high level, the proposed Data Plan Agent API comprises the following components:

  1. Mechanism to query user data plan status.
  2. Mechanism to query the DPA for data plan offers for the user.
  3. Mechanism to make changes to the user's data plan (e.g., purchase a new plan).
  4. Mechanism to verify if a user is eligible to purchase a particular data plan.
  5. Mechanism for GTAF to register MSISDNs with the DPA.
  6. Mechanism for GTAF to verify if the DPA is in a healthy state.

The rest of this document elaborates on each of these API components. Unless explicitly noted, all communications MUST happen over HTTPS (with a valid DPA SSL certificate). Depending on the actual features being supported, an operator MAY choose to implement all or a subset of these API components.

Querying Data Plan Status

GTAF-DPA Interaction

GTAF-DPA Interaction

Figure 4. Call flow to request and receive user data plan information.

Figure 4 illustrates the call flow associated with a client querying about the user's data plan status and other data plan information. This call flow is shared for API calls triggered by the client on UE.

  1. The client requests data plan status and/or other information by calling a private Google API. The client includes the user key in the request to GTAF.
  2. GTAF uses the user key to query the operator's DPA.
  3. GTAF returns the requested information to the client.

Steps 1 and 3 in Figure 4 are private Google APIs and are therefore not further described. Step 2 is a public API described hereafter. The DPA MUST respect the Cache-Control: no-cache HTTP header when serving these API calls from GTAF.

All timestamp fields defined below MUST follow the extended ISO 8601 profile defined in RFC 3339.

Plan Status

GTAF issues the following HTTP request to get the plan status:

GET DPA_URL/{userKey}/planStatus?key_type={CPID,MSISDN}

The format of the response is a JSON object representing a PlanStatus.

{
  "plans": [{
    "planName": "ACME1",
    "planId": "1",
    "planCategory": "PREPAID",
    "expirationTime": "2017-01-29T01:00:03.14159Z",
    "planModules": [{
      "moduleName": "Giga Plan", // req.
      "trafficCategories": ["GENERIC"],
      "expirationTime": "2017-01-29T01:00:03.14159Z",
      "overUsagePolicy": "BLOCKED",
      "maxRateKbps": "1500",
      "description": "1GB for a month", // req.
      "flexTimeWindows": [{
        "weeklyRecurrenceDays": [
          "WORKDAY"
        ],
        "accessBlocked": false,
        "startTime": {
          "hours": 2,
          "minutes": 5,
          "seconds": 30,
          "nanos": 500000000
        },
        "endTime": {
          "hours": 5,
          "minutes": 5,
          "seconds": 30,
          "nanos": 500000000
        },
        "timeZone": "US/Pacific",
        "discountPercentage": 50
      }],
      "coarseBalanceLevel": "HIGH_QUOTA"
    }]
  }],
  "languageCode": "en-US", // req.
  "operatorBrandName": "Test operator", // req.
  "expireTime": "2018-06-14T08:41:27-07:00", // req.
  "updateTime": "2018-06-07T07:41:22-07:00", // req.
  "title": "Prepaid Plan" // req.
}

The request SHALL include an Accept-Language header indicating the language that the human readable strings (e.g., plan descriptions) should be in.

For post-paid plans, expirationTime MUST be the plan recurrence date (i.e., when data balance gets refreshed/reloaded).

Each plan module may contain multiple Plan Module Traffic Category (PMTCs)to model the case where a plan module is shared among multiple apps (e.g., 500 MB for game and music). The following PMTCs are pre-defined: GENERIC, VIDEO, VIDEO_BROWSING, VIDEO_OFFLINE, MUSIC, GAMING, SOCIAL and MESSAGING. It is expected that operators will contact individual Google teams to agree on the set of traffic categories and their semantics that are relevant for different Google applications.

Finally, we introduce flexTimeWindows to represent off-peak data plans, or more general, rate-varying data plan based on time of the day. The absence of flexTimeWindowsimplies that the same charging rate is applied throughout the lifetime of a data plan.

Querying Plan Offers

GTAF issues the following HTTP request to get plan offers from the operator:

GET DPA_URL/{userKey}/planOffer?key_type={CPID,MSISDN}&context={purchaseContext}

The optional context parameter provides the application context the request is made in. Usually this is a string that the application passes to the operator through GTAF.

The response body contains an instance of a PlanOffer.

{
    "offerInfo": {
      "promoMessage": "Unlimited Videos for 30 days.", // req.
      "moreInfoURL": "http://example.com/learnmore",
      "operatorBrandName": "Amazing operator",
      "operatorLogoUrl": "https://gstatic.com/operator_logo.jpg" // req.
    },
    "offers": [
      {
        "planName": "ACME Red", // req.
        "planId": "turbulent1", // req.
        "planDescription": "Unlimited Videos for 30 days.", // req.
        "promoMessage": "Binge watch videos.",
        "languageCode": "en_US", // req.
        "overusagePolicy": "BLOCKED",
        "cost": { // req.
          "currencyCode": "INR",
          "units": "300",
          "nanos": 0
        },
        "duration": "2592000s",
        "offerContext": "YouTube",
        "trafficCategories": ["VIDEO"],
        "quotaBytes": "9223372036850"
      }
    ],
    "expireTime": "2019-03-04T00:06:07Z" // req.
}

The order of the data plan(s) in the offers array SHALL determine the order in which data plan(s) are presented to users. Further, if the application can present only x plans due to UI or other limitations and the response contains y > x plans only the first x plans SHALL be presented. GTAF shares only upto 10 plans if the application querying for offers is Mobile Data Plan UI which is part of Google Play Services. This is to ensure good user experience for users of Google Play Services. If a plan costs more than user's remaining wallet balance, such a plan will not be presented to the user.

The strings in offerInfo are intended to allow the user to read more about the offer, and also include a way to opt-out from receiving more offers from inside applications. The reason for having these fields is that some operators do not need end-user consent to allow in-app purchases but rather require a mechanism for users to opt-out. Note that the operator MUST have a mechanism to fulfill a purchase request for any offer extended to the user.

The request SHALL include an Accept-Language header indicating the language that the human readable strings (e.g., plan descriptions) should be in.

Data Purchase

The purchase plan API defines how GTAF can purchase plans through the DPA. The GTAF initiates the transaction to purchase one data plan to the DPA. The request SHALL include a unique transaction identifier (transactionId) to trace requests and avoid duplicate transaction execution. The DPA MUST respond with a success/failure response.

Transaction Request

Once it receives a request from a client, GTAF issues a POST request to the DPA. The URL of the request is:

POST DPA_URL/{userKey}/purchasePlan?key_type={CPID,MSISDN}

where userKey is either a CPID or MSISDN. The body of the request is an instance of TransactionRequest which includes the following fields:

{
  "planId": string,         // Id of plan to be purchased. Copied from
                            // offers.planId field returned from a
                            // Upsell Offer request,
                            // if available. (req.).
  "transactionId": string,  // Unique request identifier (req.)
  "offerContext": string,   // Copied from from the
                            // offers.offerContext, if available.
                            // (opt.)
  "callbackUrl": string     // URL that the DPA can call back with response once
                            // it has handled the request.
}

Transaction Response

The DPA SHALL return the common error causes in case of error. Additionally, the following error codes represent failed transaction outcomes:

  • The DPA returns a 400 BAD REQUEST error code indicating to GTAF that the purchased plan ID is invalid.
  • The DPA returns a 402 PAYMENT REQUIRED error code indicating to GTAF that user does not have sufficient balance to complete the purchase.
  • The DPA returns a 409 CONFLICT error code indicating to GTAF that the plan to be purchased is incompatible with the user's current product mix. For example, if the operator data plan policy disallows mixing postpaid and prepaid plans, attempting to purchase a prepaid plan for a postpaid user will therefore lead to a 409 CONFLICT error.
  • The DPA returns a 403 FORBIDDEN error code indicating to GTAF that the current transaction is a duplicate of a previously issued transaction. The DPA SHOULD return the following error causes in response:
    • If the previous transaction was a failure, error cause indicating the reason for failure.
    • If the previous transaction was successful, DUPLICATE_TRANSACTION.
    • If the previous transaction is still in queue, REQUEST_QUEUED.

The DPA SHALL generate a 200-OK response only for a successfully executed transaction or a queued transaction. In case of a queued transaction the DPA shall only fill the transaction status and leave other fields in the response empty. The DPA MUST call GTAF back with a response once a queued transaction has been handled. The body of response is an instance of TransactionResponse which includes the following details:

{
  "transactionStatus": "SUCCESS",

  "purchase": {
    "planId": string,               // copied from request. (req.)
    "transactionId": string,        // copied from request. (req.)
    "transactionMessage": string,   // status message. (opt.)
    "confirmationCode": string,     // DPA-generated confirmation code
                                    // for successful transaction. (opt.)
    "planActivationTime" : string,  // Time when plan will be activated,
                                    // in timestamp format. (opt.)
  },

  // walletInfo is populated with the balance left in the user's account.
  "walletBalance": {
    "currencyCode": string,       // 3-letter currency code defined in ISO 4217.
    "units": string,              // Whole units of the currency amount.
    "nanos": number               // Number of nano units of the amount.
  }
}

If the planActivationTime is missing, GTAF SHALL assume that the plan has been activated.

GTAF MAY issue the following request to pass the user consent preference to the carrier.

POST DPA_URL/{userKey}/consent?key_type={userKey}

where userKey is either a CPID or MSISDN. The body of the request is an instance of SetConsentStatusRequest.

If successful, the response body should be empty.

Eligibility

GTAF MAY issue the following eligibility request to check whether a user is eligible to purchase a plan.

GET DPA/{userKey}/Eligibility/{planId}?key_type={CPID,MSISDN}

Note that planId is the unique identifier for the plan that can be used to purchase the plan on behalf of the user (See Data Purchase). If planId is not specified the DPA MUST return all plans purchasable by that user.

The DPA SHALL return the common error causes in case of error. Additionally, the DPA SHALL return an error in the following error cases:

  • The DPA returns a 400 BAD REQUEST error code indicating to GTAF that planId is invalid.
  • The DPA returns a 409 CONFLICT error code indicating that planId is incompatible with the user's data plan.

Otherwise, the DPA SHALL return a 200-OK response. The format of a successful EligibilityResponse is:

{
  "eligiblePlans":
  [
   {
    "planId": string,   // Plan identifier. Can be used to
                        // refer to the plan during
                        // offers, etc. (req.)
   }
  ]
}

When the request includes a planId the response includes only that plan. Otherwise, the list includes all the plans the user is eligible to purchase. In the case where planId is empty and the DPA does not support returning the list of eligible plans it MUST return a 400 BAD REQUEST error.

MSISDN registration endpoint

To serve applications that have access to MSISDN, GTAF will register the MSISDN with the DPA. GTAF registers MSISDN only when there are applications served by the Google Mobile Data Plan Sharing API, wherein the DPA sends information to GTAF using Google APIs. To register MSISDN, GTAF will make a POST request to the DPA:

POST DPA_URL/register

The body of the request will be an instance of RegistrationRequest.

{
  "msisdn": "<msisdn_string>"
}

If the registration of the MSISDN is successful, then the DPA MUST return a 200 OK response including RegistrationResponse. The format of the JSON is:

{
  // msisdn that was registered.
  "msisdn": "<msisdn_string>",
  // time after which DPA will not send updates to GTAF.
  "expirationTime": string
}

The DPA SHOULD then send updates about the user's data plan to GTAF until expirationTime has passed.

If an error occurs, an ErrorMessage should be returned:

{
    "error": "<error message>",
    "cause": enum(ErrorCause)
}

The full list of possible cause values and HTTP status codes for different error conditions is available here. In particular, if an MSISDN registration request is received for a user who is roaming or who has not opted to sharing data plan information with Google, the DPA MUST return HTTP status code 403.

Monitoring API

Some use cases require GTAF to monitor the DPA and detect DPA failures. For those use cases, we have defined a monitoring API.

API Definition

The monitoring API should be available via HTTP GET request at the following URL:

DPA_URL/dpaStatus

If the DPA and all of its backends are operating correctly, the DPA should respond to this query with HTTP status code 200 and a response body which has an instance of DpaStatus.

{
    "status": enum(DpaStatusEnum),
    "message": "<optional human-readable status description>"
}

If the DPA or any of its backends are not operating correctly, it should respond with HTTP status code 500 and a response body which has an instance of DpaStatus.

DPA Behavior

When a failure is detected, the DPA must return the "UNAVAILABLE" status for all dpaStatus queries. In addition, it must cease sending data plan information with long cache periods. It may cease sending responses with long cache periods in one of two ways:

  1. Start setting short cache expiry times.
  2. Cease sending data plan information entirely.

GTAF Behavior

GTAF will poll dpaStatus periodically. When it detects a DPA failure (based on the "UNAVAILABLE" response), it will clear its cache for the operator.

Error Cases

In case of an error, the DPA is expected to return an HTTP status code corresponding to one of the following:

  • User is currently roaming and DPA query is disabled for this user. The DPA returns a 403 error.
  • The DPA returns a 404 NOT_FOUND error code indicating to GTAF that the user key is invalid (i.e., non-existing user key).
  • The DPA returns a 410 GONE error code indicating to GTAF that the client should get a new user key if key_type = CPID and the CPID has expired.
  • The DPA returns a 501 NOT_IMPLEMENTED error code indicating that it does not support this call.
  • Service temporarily unavailable. The DPA returns a 503 SERVICE UNAVAILABLE with the Retry-After header indicating when a new request can be attempted.
  • The DPA returns a 500 INTERNAL SERVER ERROR error code for all other unspecified errors.
  • The DPA returns a 429 TOO_MANY_REQUESTS error with the Retry-After header indicating that GTAF is making too many requests to the DPA.
  • The DPA returns a 409 CONFLICT error indicating that the request cannot be completed due to a conflict with the current state of the DPA.

In all the error cases, the body of the HTTP response MUST include a JSON object with more information about the error. The error response body MUST contain an instance of ErrorResponse.

{
  "error": string,
  "cause": enum(ErrorCause)
}

The cause values currently defined are listed as part of ErrorCause API reference.

Otherwise, the DPA returns a 200 OK. We note that these cause values are used for all responses.