Hacking in everyday life (fun with the Sprint API)

Posted by Matthew Watkins on July 24, 2017

Let me explain the situation I found myself in last week:

If you didn’t already know, Sprint is offering a free year of unlimited service through the end of July if you port your non-Sprint number to them. It’s a great deal, but if you are not a Verizon customer, they really make you work for it. If you’re with a smaller carrier, the free years page will probably say you are ineligible, even if you have an eligible type of device. That’s because Sprint maintains its own database of phones with some indicator on each record saying whether the phone is on the Sprint network or not (you heard me right: a database of phones that are not on their network). So, if your carrier (like mine) has not told Sprint that your phone is not on the Sprint network, the Sprint system assumes you are ineligible for the offer.

The solution is to create a support case with Sprint to get your device info (WiFi MAC address, IMEI number, phone number, make/model, and current carrier) added to that database. From the experience of family members who tried this, I know it would take up to three days for the information to get processed into the database and reflected on the free year page, and potentially longer for me to get the email from Sprint saying everything is hunky-dory. But time was of the essence, so I would have to check the free year page every few hours to try and find out when the offer was available for each of the devices I wanted to port. What a hassle!

This is where being a developer comes in handy.

I fired up my trusty Postman Interceptor Chrome extension and fired off a query for my still-ineligible phone. And there in the traffic history, I saw an AJAX HTTP request to a promising-looking sprint.com endpoint that returned some promising-looking JSON:

{
    "errors": [
        {
            "errorCode": "COULD_NOT_VALIDATE_SERIAL_NUMBER",
            "errorMessage": "Server.704:NMS returned status_code=49, status_text=INVALID_PHONE_OWNERSHIP: Phone owner can not be PLBL."
        }
    ]
}

The request was a GET, but it was pretty gnarly: all sorts of message IDs and tokens and timestamps. Luckily, Postman makes modifying and replaying it easy. So I started stripping off headers to see which ones I could sacrifice. Fortunately, most of the headers my browser had sent turned out to be unnecessary, and of the remaining, required headers, none were actually validated for accuracy– the Sprint API just requires some value in those fields. At the end of the day, I could trim the entire HTTP request down to this (where xxxxxxxxxxxx represent the IMEI of the device I wanted to query):

GET /api/digital/byod/v1/foreign-device/xxxxxxxxxxxx HTTP/1.1
Host: www.sprint.com
messageid: 1000
enterprisemessageid: ECMW593313374
messagedatetimestamp: 2017-07-19T22:56:59
applicationuserid: LVO
applicationid: LVO

Awesome. But it’s still tedious to have to do this manually every few hours. Time to automate it. I could have set up a chron job on my machine for this, but this is actually a perfect opportunity to bring in my good friend Google Apps Script. I created a new script and wrote the following, simple function and setup a trigger to have Google run it every 15-minutes:

function run() {
  if (isReady('xxxxxxxxxxxx')) {
    GmailApp.sendEmail('myemail@mydomain.com', 'YOUR PHONE IS IN THE DB NOW!', 'Go sign up for your free year');
    // Delete the 15-minute trigger I manually created earlier so I don't get spammed
    ScriptApp.deleteTrigger(ScriptApp.getProjectTriggers()[0]);
  } else {
    Logger.log('The phone is NOT in the DB'); 
  }
}

function isReady(imei) {
  Logger.log('Calling the Sprint API');
  var responseText = UrlFetchApp.fetch('https://www.sprint.com/api/digital/byod/v1/foreign-device/' + imei, {
    'method': 'get',
    'headers': {
      'messageid': '1000',
      'enterprisemessageid': 'ECMW593313374',
      'messagedatetimestamp': '2017-07-19T22:56:59',
      'applicationuserid': 'LVO',
      'applicationid': 'LVO'
    },
    'muteHttpExceptions': true
  }).getContentText();

  // Log the response from the API
  Logger.log(responseText);

  // Parse it and return whether the object exists and has no errors
  var response = JSON.parse(responseText);
  return response && !response.errors;
}

I received an email the next day from my script, informing me that I could now pounce on the free year plan. I figured I must have had a bug in the program, so I checked the logs. And there was the last logged API response, happily confirming that I was indeed now eligible for 365 days of unlimited LTE:

{
  "byodDetails": {
    "serialNo": "xxxxxxxxxxxx",
    "deviceSKU": "yyyyyyyyyyyyy",
    "netCompatibility": null,
    "iccId": null,
    "simKitInfo": [
      {
        "simSKU": "zzzzzzzzzzzzzzz",
        "simPartNumber": "aaaaaaaaaaaa",
        "simPriority": "1",
        "simSKUPricingInfo": {
          "finalPrice": 2.99,
          "basePrice": 2.99
        }
      }
    ]
  }
}

The point I want to make is that setting up Postman, playing with the request, and writing my Google Apps Script took all of one hour. One hour to automate what would have been a tedious, multi-day process of manual verification for each of my household’s devices each day.

It got me wondering: what else can I hack? What other APIs are out there? Where else can I write a bit of code and get a few hours of my life back?

What in your life can you automate?

This post first appeared on Another Dev Blog