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:
- Mechanism to query user data plan status.
- Mechanism to query the DPA for data plan offers for the user.
- Mechanism to make changes to the user's data plan (e.g., purchase a new plan).
- Mechanism to verify if a user is eligible to purchase a particular data plan.
- Mechanism for GTAF to register MSISDNs with the DPA.
- 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
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.
- 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.
- GTAF uses the user key and a client identifier to query the operator's DPA. The supported client identifiers are mobiledataplan and youtube. When the DPA receives a call with one of these client identifiers, it MUST respond with plan information that can be used by the client.
- GTAF returns the requested information to the client and the plan information is cached by GTAF until the expiration time specified by the DPA.
Steps 1 and 3 in Figure 4 are private Google APIs and are therefore not
described further. 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.
Plan Status
GTAF issues the following HTTP request to get the plan status:
GET DPA_URL/{userKey}/planStatus?key_type={CPID,MSISDN}&client_id=CLIENT_ID
The client on behalf of which GTAF is contacting the DPA is identified using CLIENT_ID. Depending on the agreement between the Google client and carrier the DPA can customize the response to GTAF. 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", // req.
"planModules": [{
"moduleName": "Giga Plan", // req.
"trafficCategories": ["GENERIC"],
"expirationTime": "2017-01-29T01:00:03.14159Z", // req.
"overUsagePolicy": "BLOCKED",
"maxRateKbps": "1500",
"description": "1GB for a month", // req.
"coarseBalanceLevel": "HIGH_QUOTA"
}]
}],
"languageCode": "en-US", // req.
"expireTime": "2018-06-14T08:41:27-07:00", // req.
"updateTime": "2018-06-07T07:41:22-07:00", // req.
"title": "Prepaid Plan"
"planInfoPerClient": {
"youtube": {
"rateLimitedStreaming": {
"maxMediaRateKbps": 256
}
}
}
}
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.
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}&client_id=CLIENT_ID&context={purchaseContext}
The client on behalf of which GTAF is contacting the DPA is identified using CLIENT_ID. Depending on the agreement between the Google client and carrier the DPA can customize the response to GTAF. 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.
{
"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 MAY 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.
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 mechanism through which
the user will be charged for any purchase can be communicated with GTAF using
formOfPayment
option in the response.
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}&client_id=CLIENT_ID
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.
Consent
GTAF MAY issue the following request to pass the user consent preference to the carrier.
POST DPA_URL/{userKey}/consent?key_type={CPID,MSISDN}&client_id=CLIENT_ID
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 ErrorResponse 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:
- Start setting short cache expiry times.
- 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.
Internationalization
GTAF requests to the DPA include an Accept-Language header indicating the language that the human readable strings (e.g., plan descriptions) should be in. Further, DPA responses (PlanStatus, PlanOffers) include a required languageCode field whose value is the BCP-47 language code (e.g., "en-US") of the response.
If the DPA does not support the language the user requested, it can use a default language and use the languageCode field to indicate its choice.