---
title: Routing Data from Notehub to a Custom Cloud Endpoint
description: Learn how to write a cloud service that receives data from a Notehub route, using a variety of popular backend languages and frameworks.
source_url: https://dev.blues.io/example-apps/samples/routing-data-from-notehub-to-a-custom-cloud-endpoint/
canonical_url: https://dev.blues.io/example-apps/samples/routing-data-from-notehub-to-a-custom-cloud-endpoint/
markdown_url: https://dev.blues.io/example-apps/samples/routing-data-from-notehub-to-a-custom-cloud-endpoint.md
---

# Routing Data from Notehub to a Custom Cloud Endpoint

## Introduction

This sample app showcases how to receive data from a [Notehub route](https://dev.blues.io/notehub/notehub-walkthrough.md#routing-data-with-notehub) on a custom cloud endpoint using several popular backend languages and frameworks. These examples give you the flexibility to self-host a service and integrate Notehub data directly into your own systems.

### Wireless Connectivity with Blues

This sample app is built around the [Blues Notecard](https://blues.com/products/notecard/) and [Blues Notehub](https://blues.com/notehub/).

The **Blues Notecard** is the easiest way for developers to add secure, robust, and affordable pre-paid wireless connectivity to their microcontroller or single-board computer of choice. Notecard is a System-on-Module (SoM) that combines pre-paid data, low-power hardware (\~8μA-18μA when idle), and secure communications. It acts as a device-to-cloud data pump to communicate with the Blues cloud service Notehub.

**Notehub** is the Blues cloud service for routing Notecard-provided data to third-party cloud applications, deploying OTA firmware updates, and securely managing fleets of Notecards. Notehub allows for secure communications between edge devices and the cloud without certificate management or manual provisioning of devices.

## General Information

### System Hardware

The event data utilized in these examples can be provided by any combination of Notecard, host microcontroller, and sensor.

### Backend Frameworks

The examples are categorized by programming language and each utilizes a specific web framework and/or runtime to simplify the implementation.

| **Language**              | **Web Framework/Runtime** |
| ------------------------- | ------------------------- |
| [JavaScript](#javascript) | Node.js and Express.js    |
| [Python](#python)         | Flask                     |
| [C#](#c)                  | ASP.NET Core              |

### Assumptions

The sample code provided assumes the JSON event data you are routing includes at least a `body` element. For example:

```json
{
  "event": "d012d460-7992-8414-a4eb-63bc816bf100",
  "when": 1745940562,
  "file": "data.qo",
  "body": {
    "temp": 23.4
  },
  "session": "b68ffcd2-55db-4bb0-806c-b72bd852f2d7",
  "transport": "cell:lte:fdd",
  "best_id": "dev:860322068073292",
  ...
}
```

## JavaScript

Running JavaScript applications on the server requires a runtime environment such as [Node.js](https://nodejs.org/). Node.js is free, open-source, and runs on any operating system.

### Requirements

1. [Install Node.js](https://nodejs.org/en/download) (preferably the latest LTS release).
2. Install [Express.js](https://expressjs.com/), which is a free and open-source web framework built on top of Node.js.
3. A Windows, macOS, or Linux physical server or VPS.

### Implementation

1. Open your terminal (or PowerShell on Windows), create a new directory, and navigate inside it.

   ```bash
   mkdir notehub-route && cd notehub-route
   ```

2. Initialize your application using npm (Node Package Manager).

   ```bash
   npm init -y
   ```

3. Edit your `package.json` file so the `scripts` section looks like the following. This will instruct Node.js to start the script we are about to create.

   ```json
   "scripts": {
      "start": "node index.js"
   }
   ```

4. In the root of `notehub-route` create a file called `index.js`.

5. The `index.js` file is where all of your application logic will exist to receive routed data from Notehub via a POST request. The following is an example implementation with inline comments and a placeholder function where you will want to implement your own functionality to process the event (e.g. insert records into a database).

   Please note that if you end up using a [JSONata expression](https://dev.blues.io/guides-and-tutorials/notecard-guides/using-jsonata-to-transform-json-in-notehub.md) in your route, you may have to adjust the application logic, as this example assumes there will be a `body` element in the routed JSON.

   ```javascript
   const express = require('express');
   const app = express();

   app.use(express.json());

   // POST to /data and extract req.body.body from Notehub event
   app.post('/data', async (req, res) => {

     // get the "body" object from incoming Notehub event JSON
     const payload = req.body && req.body.body;

     if (!payload) {
       return res.status(500).json({ error: 'Event is missing body element' });
     }

     try {
       // the `processPayload` function is where your custom logic will be required
       // e.g. insert records into a database or forward to another service
       processPayload(payload);

       // respond to Notehub with a success
       res.status(200).json({ status: 'ok' });
     } catch (err) {
       // if your custom logic throws an error, catch it here
       console.error('Processing error:', err);
       res.status(500).json({ error: err });
     }
   });

   // placeholder function
   function processPayload(data) {
     console.log('Received payload:', data);
   }

   // start the server on an open and available port
   const PORT = process.env.PORT || 3000;
   app.listen(PORT, () => {
     console.log(`Listening on port ${PORT}`);
   });
   ```

6. Once your `index.js` file is complete, run the following command to start your service.

   ```bash
   npm start
   ```

   If running this locally, you can access the service here:

   ```plaintext
   http://localhost:3000/data
   ```

7. When [testing your service](#testing-your-service) locally, you should see a response like this in your terminal (where `{ test: 1 }` is the `body` element from the POSTed JSON event):

   ```bash
   > notehub-route@1.0.0 start
   > node index.js

   Listening on port 3000
   Received payload: { test: 1 }
   ```

## Python

While Python scripts can run on any server, in order to process POST requests over web protocols, it's best to use a framework like [Flask](https://flask.palletsprojects.com/en/stable/). Flask is a "micro web framework" for Python, designed to be lightweight and flexible.

### Requirements

1. Install [Python 3](https://www.python.org/).
2. Install [Flask](https://flask.palletsprojects.com/en/stable/installation/).
3. A Windows, macOS, or Linux physical server or VPS.

### Implementation

1. Create a new directory and navigate inside it.

   ```bash
   mkdir notehub-route && cd notehub-route
   ```

2. In the root of `notehub-route`, create a file called `app.py`.

3. The `app.py` file is where all of your application logic will exist to receive routed data from Notehub via a POST request. The following is an example implementation with inline comments and a placeholder function where you will want to implement your own functionality to process the event (e.g. insert records into a database).

   Please note that if you end up using a [JSONata expression](https://dev.blues.io/guides-and-tutorials/notecard-guides/using-jsonata-to-transform-json-in-notehub.md) in your route, you may have to adjust the application logic, as this example assumes there will be a `body` element in the routed JSON.

   ```python
   from flask import Flask, request, jsonify

   app = Flask(__name__)

   # POST to /data and extract body from Notehub event
   @app.route('/data', methods=['POST'])
   def data_endpoint():
       payload = request.get_json(force=True, silent=True) or {}
       body = payload.get('body')

       if body is None:
           return jsonify(error='Event is missing body element'), 500

       try:
           # the `process_payload` function is where your custom logic will be required
           # e.g. insert records into a database or forward to another service
           process_payload(body)
           return jsonify(status='ok'), 200
       except Exception as e:
           app.logger.error('Processing error: %s', e)
           return jsonify(error=e), 500

   def process_payload(data):
       # placeholder function
       print('Received payload:', data)

   if __name__ == '__main__':
       # include debug=False for production
       app.run(host='0.0.0.0', port=5123)
   ```

4. Once your `app.py` file is complete, run the following command to start your service.

   ```bash
   python3 app.py
   ```

   If running this locally, you can access the service here:

   ```plaintext
   http://localhost:5123/data
   ```

5. When [testing your service](#testing-your-service) locally, you should see a response like this in your terminal (where `{ test: 1 }` is the `body` element from the POSTed JSON event):

   ```bash
   * Serving Flask app 'app'
   * Debug mode: off
   WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
   * Running on all addresses (0.0.0.0)
   * Running on http://127.0.0.1:5123
   * Running on http://192.168.0.189:5123
   Press CTRL+C to quit
   Received payload: {'test': 1}
   127.0.0.1 - - [02/May/2025 09:34:53] "POST /data HTTP/1.1" 200 -
   ```

## C\#

Modern [C#](https://dotnet.microsoft.com/en-us/languages/csharp) applications running on [.NET](https://dotnet.microsoft.com/en-us/) are cross-platform and can be deployed on Windows, macOS, or Linux. [ASP.NET Core](https://dotnet.microsoft.com/en-us/apps/aspnet) is Microsoft's framework for building and deploying web applications on [Kestrel](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-9.0) (all platforms) or [IIS](https://www.iis.net/) (Windows only).

### Requirements

1. Install the [.NET 9 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0).
2. Depending on your operating system, you may have to manually add the .NET SDK to your PATH, for example:
   ```bash
   export DOTNET_ROOT="/usr/local/share/dotnet"
   export PATH="$PATH:/usr/local/share/dotnet"
   ```
3. (Optional - Windows only) Install/enable [IIS](https://learn.microsoft.com/en-us/iis/application-frameworks/scenario-build-an-aspnet-website-on-iis/configuring-step-1-install-iis-and-asp-net-modules).
4. A Windows, macOS, or Linux physical server or VPS.

### Implementation

1. Create a new directory and navigate inside it.

   ```bash
   mkdir notehub-route && cd notehub-route
   ```

2. Initialize a new ASP.NET Core application.

   ```bash
   dotnet new web --framework net9.0
   ```

3. In the root of `notehub-route`, open the file called `Program.cs`.

4. The `Program.cs` file is where all of your application logic will exist to receive routed data from Notehub via a POST request. The following is an example implementation with inline comments and a placeholder function where you will want to implement your own functionality to process the event (e.g. insert records into a database).

   Please note that if you end up using a [JSONata expression](https://dev.blues.io/guides-and-tutorials/notecard-guides/using-jsonata-to-transform-json-in-notehub.md) in your route, you may have to adjust the application logic, as this example assumes there will be a `body` element in the routed JSON.

   ```csharp
   using System.Text.Json;
   using Microsoft.AspNetCore.Builder;
   using Microsoft.Extensions.Hosting;
   using Microsoft.AspNetCore.Http;

   var app = WebApplication.CreateBuilder(args).Build();

   // POST to /data and extract body from Notehub event
   app.MapPost("/data", async (HttpContext ctx) =>
   {
       JsonElement? root = null;
       try
       {
           root = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
       }
       catch { }

       if (root == null || !root.Value.TryGetProperty("body", out var body))
           return Results.BadRequest(new { error = "Event is missing body element" });

       try
       {
           // the `ProcessPayload` function is where your custom logic will be required
           // e.g. insert records into a database or forward to another service
           ProcessPayload(body);
           return Results.Ok(new { status = "ok" });
       }
       catch (Exception ex)
       {
           app.Logger.LogError(ex, "Processing error");
           return Results.Json(
               new { error = "Internal Server Error" },
               statusCode: 500
           );
       }
   });

   app.Run();

   static void ProcessPayload(JsonElement data)
   {
       // placeholder function
       Console.WriteLine("Received payload: " + data);
   }
   ```

5. Once your `Program.cs` file is complete, run the following command to start your service.

   ```bash
   dotnet run --urls "http://localhost:5123"
   ```

   The `urls` argument is optional; use if you want to override the default 5000 port.

   If running this locally, you can access the service here:

   ```plaintext
   http://localhost:5123/data
   ```

6. When [testing your service](#testing-your-service) locally, you should see a response like this in your terminal (where `{ test: 1 }` is the `body` element from the POSTed JSON event):

   ```bash
   Using launch settings from /Users/me/apps/notehub-route/Properties/launchSettings.json...
   Building...
   info: Microsoft.Hosting.Lifetime[14]
         Now listening on: http://localhost:5123
   info: Microsoft.Hosting.Lifetime[0]
         Application started. Press Ctrl+C to shut down.
   info: Microsoft.Hosting.Lifetime[0]
         Hosting environment: Development
   info: Microsoft.Hosting.Lifetime[0]
         Content root path: /Users/me/apps/notehub-route
   Received payload: {
       "test": 1
     }
   ```

## Testing Your Service

1. You should now be able to use your service with a tool like [Postman](https://www.postman.com/). Simply copy the full JSON from the **JSON** tab in the Notehub event you'd like to test, and use that as the `body` of your POST request.

2. If the service is deployed to a remote server, you can return to Notehub and create a new route using the **General HTTP/HTTPS Request/Response** type. If you haven't already, [follow the provided guide](https://dev.blues.io/guides-and-tutorials/routing-data-to-cloud/general-http-https.md) to learn how routing works in Notehub.

   When setting up your route, be sure to provide the URL of your remote endpoint in the **URL** field. If required by your server's firewall, you may also need to whitelist the IPs [specified in the Notehub Walkthrough](https://dev.blues.io/notehub/notehub-walkthrough.md#routing-data-with-notehub).

   ![example notehub route setup](https://dev.blues.io/images/example-apps/routing-data-custom/notehub-route.png?v=8a4230a5)

3. You can now start routing data from Notehub by either [manually routing existing events](https://dev.blues.io/notehub/notehub-walkthrough.md#manually-routing-events) or allowing new events to utilize the route.

## Additional Resources

- [Routing Data with Notehub](https://dev.blues.io/notehub/notehub-walkthrough.md#routing-data-with-notehub)
- [Routing Data to Cloud Tutorial](https://dev.blues.io/guides-and-tutorials/routing-data-to-cloud.md)
