Learn how to integrate Withthegrid platform with KPN.

Connecting a device

In the following tutorial, we connect a Dragino LDS02 LoRaWAN Door Sensor to the platform via KPN Things.

You can also find the supporting material to help you kick-start the integration.

type JsonObject = { [key: string]: Json };

const kpnDeviceTypes = {
  dragino: {
    lds01: "dragino-lds01",

const deviceTypeHashIds = {
  dragino: {
    lds01: "TO DO",

function handle(args: Arguments): Result {
  const body = JSON.parse(JSON.stringify(args.request.body?.data));

  let deviceTypeHashId;
  switch (args.request.headers["device-type"]) {
    case kpnDeviceTypes.dragino.lds01:
      deviceTypeHashId = deviceTypeHashIds.dragino.lds01;

      throw new Error(
        "Device type hash id is not available " +

  const deviceIdentifier = body[0].bn.substring(15, 31);
  if (typeof deviceIdentifier !== "string") {
    throw new Error("Device identifier not found!");

  return {

 * Validate request.
 * @throws Throws an error when the request is invalid.
function validateRequest(request: WebRequest, data: JsonObject) {
  if (request.body?.type !== "json") {
    throw new Error("Body must be JSON.");

To be able to send a downlink message to devices via KPN Things, it is important to correctly access the API. The "KPN Things Developer Manual" and the "KPN Things API's public documentation" provides a detailed information on how this can be done. Here, we conclude the most important steps required to send a raw payload.

Each time, before we want to connect to the device via KPN Things API, we need to request an access token. The access token can be requested with the following code snippet.

function kpnGetBearerToken(exec: Exec): string {
  const args: SendRequestArgs = {
    url: kpnRequestTokenUrl,
    method: 'post',
    headers: {
      "Content-Type": "application/json; charset=utf-8"
    body: {
        "grant_type": "client_credentials",
        "audience": kpnAudience,
        "client_id": kpnClientID,
        "client_secret": kpnClientSecret
  const response: any = exec.sendRequest(args);
  if(response.body?.type != 'json') {
    throw new Error("Failed to get KPN access token!");

The following inputs need to be defined.

const kpnTenantID = 'TO DO'
const kpnDownlinkURL = '';
const kpnRequestTokenUrl = '' + kpnTenantID + '/oidc/idp/c1/token';
const kpnAudience = '4dc82561-f65f-523g-dek9-6c79ec314f02';
const kpnClientID = 'TO DO'
const kpnClientSecret = 'TO DO'

The KPN kpnTenantID can be found by completing the following steps, while the steps to obtain kpnClientID (API key ID) and the kpnClientSecret (API key secret key) are explained here.

The last steps are to construct the request body, downlink URL, request header, and to execute the POST request.

const body = '[{"bn":"urn:dev:DEVEUI:'+devEUI+':", "n":"payloadHex", "vs": "' + payload + '"}]';
const url = kpnDownlinkURL + "?port=" + port.toString(10);
const bearerToken = kpnGetBearerToken(exec);
if (bearerToken === null || bearerToken.length === 0) {
  throw new Error(`BearerToken is null or length is ${bearerToken.length}`);
const header = {
  "Authorization": "Bearer " + bearerToken,
  "Accept": "application/vnd.kpnthings.actuator.v1.response+json",
  "Content-Type": "application/json"

const response = exec.sendRequest({url, method: 'post', body: body, headers: header});

In this last part, the user needs to provide the devEUI of the device of interest, port (e.g. 2), and a raw payload in a hexadecimal format.

Last updated