The StarCat, an alien geek who is coming from the outer space ;)

SMS2API

Technical Documentation

Overview

The SMS2API is a simple application forwards the received SMS messages to an HTTP REST API. The message data is being transferred as a JSON object via HTTP as a POST request. The app only forwards the messages received while the application is running. (in the foreground or at the background). The app doesn't forward previous SMS messages stored on the device. Due to this design, the app IS NOT GOOGLE PLAY COMPATIBLE, but only requests permission for android.permission.RECEIVE_SMS and uses android.permission.INTERNET as part of the normal permissions.

Endpoint requirements

The SMS2API application makes an HTTP POST request on each received message. The content type of the HTTP request is application/json , the encoding is UTF8. The HTTP endpoint is defined by the user on the app's UI. The application assumes an application/json response containing a valid JSON object in the body. This behavior is the same for all HTTP status codes, so in the case of 401 or in the case of 500 the valid JSON body is also required! In the case of HTTP status 200 reply, the "success" counter does increment. In the case of HTTP status 401 or 500 the "failed" counter increment the application UI. UI.

JSON object

The posted JSON object contains all the received SMS data and contains two more extra fields to help to integrate. These fields are the apiKey and the userDefinedId. These are simple string values located at the root level of the JSON object. As the names show, these fields are designed to be used for authentication and device-identification purposes but feel free to use them for different purposes for your use case. The application doesn't check or modify the values of these fields.

Note, these string fields are stored in the application's local storage as plain texts!

{
    apiKey: 'weiY7eirrohQu2tiOof9iehe',
    messageBody: 'Blablabla',
    originalMessage: {
        mSubId: 3,
        mWrappedSmsMessage: {
        mDataCodingScheme: 0,
        mEncodingType: 1,
        mIsStatusReportMessage: false,
        mMti: 0,
        mProtocolIdentifier: 0,
        mReplyPathPresent: false,
        mStatus: 0,
        mVoiceMailCount: 0,
        messageClass: 'UNKNOWN',
        absoluteValidityPeriod: 0,
        mIndexOnIcc: -1,
        mIsEmail: false,
        mIsMwi: false,
        mMessageBody: '2',
        mMessageRef: 0,
        mMwiDontStore: false,
        mMwiSense: false,
        mOriginatingAddress: [Object],
        mPdu: [Array],
        mScAddress: '+36709996511',
        mScTimeMillis: 1633424319000,
        mStatusOnIcc: -1,
        mUserData: [Array],
        mwiCount: 0,
        mwiType: -1,
        relativeValidityPeriod: 0
        }
    },
    originatingAddress: '+36705559955',
    serviceCenterAddress: '+36709996511',
    timestampMillis: 1633424319000,
    userDefinedId: 'motoc'
}
As this example JSON object shows, the originalMessage object encapsulates the whole Android-provided SMS object.

You could learn more about the represented data at https://developer.android.com/reference/android/provider/Telephony.Sms.Intents

The outer "wrapper" objects provides the more importants fields at the root level too. These fields are the followings:

  • messageBody is the received message
  • originatingAddress is the sender's number
  • serviceCenterAddress is the number of the SMS center
  • timestampMillis shows what was the timestamp when the Android system did recive the message
  • apiKey simple extra string value
  • userDefinedId simple additional string value

Example server

var http = require('http')
http.createServer( async (req, res) => {

    // Set the proper response type
	res.setHeader('Content-Type', 'application/json')

	try {
	    
        // Create a buffer for received chunks
		const buff = []
		for await (const chunk of req) buff.push(chunk)
		
        // Get the data object & create a JSON
		const data = Buffer.concat(buff).toString()
		const message = JSON.parse(data)
		
        console.info("Message received: ", message)
		
		// ...
		// process the received message, do your business logic
		// in case of no error, return with status code 200
        res.writeHead(200, {'Content-Type': 'application/json'})
		res.write(JSON.stringify({message: `Message has been stored.`}))
		
	} catch (e) {
		
		// in case of any error, we are going to return with 500
		res.writeHead(500, {'Content-Type': 'application/json'})
		res.write(JSON.stringify({message: `Oops! Something went wrong!`}))
		
	} finally {
		res.end()
	}
	
}).listen(8080)

Appendix

The SMS2API app doesn't delete the received messages, just forward them. Due to this design, consider to use some automated message deletation tasks. Some Android phone provides this feature out-of-the box while others do not. We use Textra, a 3rd party texting app allowing a feature to delete old messages. Textra is not perfect for this task because it does not delete unread messages and has to delete them manually! If you find a better solution for this issue, please, let us know!

🤓 Happy Integration!