---
title: Web Transactions
description: If your host needs to request or receive data, to or from a 3rd party API or service, the Notecard can facilitate these requests with the web.get, web.put, web.post, and web.delete requests over cellular, WiFi, LoRa, or satellite connectivity.
source_url: https://dev.blues.io/notecard/notecard-walkthrough/web-transactions/
canonical_url: https://dev.blues.io/notecard/notecard-walkthrough/web-transactions/
markdown_url: https://dev.blues.io/notecard/notecard-walkthrough/web-transactions.md
---

# Web Transactions

If your host needs to perform web requests (e.g. `GET`, `PUT`, `POST`, or `DELETE`) with a 3rd-party API or cloud service, the Notecard can facilitate these requests with the [web.\* APIs](https://dev.blues.io/api-reference/notecard-api/web-requests/latest.md).

> **Note:**
>
> Web transactions are not supported on the Notecard for LoRa nor while using NTN mode with Starnote.

1. [Requirements for Using Web Transactions](#requirements-for-using-web-transactions)
2. [Issuing Web Transactions](#issuing-web-transactions)
3. [Parsing Web Transaction Responses](#parsing-web-transaction-responses)
4. [Storing Web Transaction Responses in DB Notefiles](#storing-web-transaction-responses-in-db-notefiles)
5. [Sending Large Payloads to Notehub](#sending-large-payloads-to-notehub)

## Requirements for Using Web Transactions

Use of any of the Notecard API's `web` requests requires the following:

1. The Notecard must be in `continuous` mode or be temporarily placed in `continuous` mode (unless you want to [store a web transaction response in a DB Notefile](#storing-web-transaction-responses-in-db-notefiles)).

   You can place your Notecard into (permanent) `continuous` mode using the [hub.set API](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-set) as shown below:

   **JSON**

   ```json
   {
     "req": "hub.set",
     "product": "com.your-company.your-name:your_product",
     "mode": "continuous"
   }
   ```

   **C/C++**

   ```cpp
   J *req = NoteNewRequest("hub.set");
   JAddStringToObject(req, "product", "com.your-company.your-name:your_product");
   JAddStringToObject(req, "mode", "continuous");

   NoteRequest(req);
   ```

   **Python**

   ```python
   req = {"req": "hub.set"}
   req["product"] = "com.your-company.your-name:your_product"
   req["mode"] = "continuous"

   card.Transaction(req)
   ```

   Alternatively, if your Notecard is in `periodic` mode, you can use the `"on":true` argument to temporarily switch to `continuous` mode while a web transaction is active. The `"seconds"` argument allows you to specify how many seconds the Notecard should remain in `continuous` mode before switching back to `periodic` (the default is `300`).

   **JSON**

   ```json
   {
     "req": "hub.set",
     "on": true,
     "seconds": 120
   }
   ```

   **C/C++**

   ```cpp
   J *req = NoteNewRequest("hub.set");
   JAddBoolToObject(req, "on", true);
   JAddNumberToObject(req, "seconds", 120);

   NoteRequest(req);
   ```

   **Python**

   ```python
   req = {"req": "hub.set"}
   req["on"] = True
   req["seconds"] = 120

   card.Transaction(req)
   ```

2. The Notecard must have an active connection to Notehub.

   When you place a Notecard in `continuous` mode, it immediately starts making a connection to Notehub. If you attempt to make any `web.*` requests before this connection is established, you'll receive the following error:

   ```json
   { "err": "web operations in continuous mode require being online (hub.set) {not-connected}" }
   ```

   You can check whether your Notecard is actively connected using the [hub.status API](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-status).

   **JSON**

   ```json
   {"req": "hub.status"}
   ```

   **C/C++**

   ```cpp
   J *req = NoteNewRequest("hub.status");

   NoteRequest(req);
   ```

   **Python**

   ```python
   req = {"req": "hub.status"}
   rsp = card.Transaction(req)
   ```

   When the `hub.status` request returns `"connected": true`, you know your Notecard has made a connection with Notehub and you are safe to perform `web.*` requests.

   ```json
   {"req":"hub.status"}
   ```

   ```json
   {"connected":true}
   ```

3. The endpoint to the 3rd-party API or cloud service must be configured as a Route in Notehub using the "Proxy for Notecard Web Requests" type.

   This allows the host to avoid hardcoded URLs, keys, and certificates, while relying on Notehub secure authentication mechanisms for performing requests.

   ![notehub proxy for web requests](https://dev.blues.io/images/reference/notecard-api/proxy-route.png?v=b3cef057)

## Issuing Web Transactions

With these steps complete, you can now use the `web.get`, `web.put`, `web.post`, and `web.delete` requests in accordance with the requirements of the remote endpoint.

### web.get

The Route shown above creates a proxy to a `GET` request to a weather endpoint of the [OpenWeatherMap API](https://openweathermap.org/api). The `route` argument corresponds to the *Alias* specified when the proxy Route is created.

**JSON**

```json
{
  "req": "web.get",
  "route": "GetWeather"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("web.get");
JAddStringToObject(req, "route", "GetWeather");

NoteRequest(req);
```

**Python**

```python
req = {"req": "web.get"}
req["route"] = "GetWeather"

rsp = card.Transaction(req)
```

A successful `web.get` response returns the remote endpoint's HTTP status code in the `result` field and the parsed JSON response in the `body` field:

```json
{
 "result": 200,
 "body": {
  "temperature": 17.2,
  "humidity": 68
 }
}
```

> **Note:**
>
> The optional `name` argument appends a URL path (and optionally query parameters) relative to the host configured in the Proxy Route — for example, `"name": "/getLatest?id=1"` would append that path to the route's base URL before the request is forwarded.

Note that you may **optionally enable caching** so that `web.get` requests return cached results to reduce latency and provide you with more control over [event credit](https://dev.blues.io/notehub/notehub-walkthrough.md#understanding-event-credits) usage.

Caching is configured on the Proxy Route itself in Notehub (set the route's **Cache** option to "Cache results in accordance with RFC 7234" and specify a "Fetch no more often than" interval in minutes). When handling a `web.get` request with caching enabled, Notehub honors the `Cache-Control` response header as per [RFC7234](https://datatracker.ietf.org/doc/html/rfc7234#section-5.2) with a minimum cache TTL of 5 minutes.

> **Note:**
>
> By default, each `web.*` request times out after 90 seconds. If you're calling an endpoint that can take longer to respond, raise (or lower) this limit with the `seconds` argument, for example `"seconds": 120`.

### web.put and web.post

For `PUT` and `POST` requests, a JSON body OR base64-encoded payload can optionally be provided using the `body` or `payload` arguments. Unlike the `note.add` API, you cannot use both at the same time in a single web transaction.

**JSON**

```json
{
  "req": "web.post",
  "route": "SensorService",
  "name": "/addReading",
  "body": { "temp": 72.32, "humidity": 32.2 }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("web.post");
JAddStringToObject(req, "route", "SensorService");
JAddStringToObject(req, "name", "/addReading");

J *body = JCreateObject();
JAddNumberToObject(body, "temp", 72.32);
JAddNumberToObject(body, "humidity", 32.2);
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "web.post"}
req["route"] = "SensorService"
req["name"] = "/addReading"
req["body"] = {"temp":72.32, "humidity":32.2}

rsp = card.Transaction(req)
```

#### Issuing web.post, web.put, and web.delete Requests Asynchronously

If your firmware does not need to wait for the result of a `web.post`, `web.put`, or `web.delete` request (or does not require the response) you can issue the request *asynchronously* and continue execution without blocking. To do this, include the `"async": true` argument in the request.

> **Note:**
>
> `async` only takes effect when the Notecard is in `continuous` mode and currently online. In other modes, the request executes synchronously regardless of this argument.

**JSON**

```json
{
  "req": "web.put",
  "route": "SensorService",
  "name": "/updateReading",
  "body": { "temp": 75.45, "humidity": 38.9 },
  "async": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("web.put");
JAddStringToObject(req, "route", "SensorService");
JAddStringToObject(req, "name", "/updateReading");

J *body = JCreateObject();
JAddNumberToObject(body, "temp", 75.45);
JAddNumberToObject(body, "humidity", 38.9);
JAddItemToObject(req, "body", body);
JAddBoolToObject(req, "async", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "web.put"}
req["route"] = "SensorService"
req["name"] = "/updateReading"
req["body"] = {"temp":75.45, "humidity":38.9}
req["async"] = True

rsp = card.Transaction(req)
```

## Parsing Web Transaction Responses

For all web requests the Notecard returns the HTTP Status Code in the `result` field. If the response also contains a body, that body is provided in the `body` field. Binary or other non-JSON responses are instead returned in a base64-encoded `payload` field.

For example, the code below shows a response from a successful `GET` request to the OpenWeatherMap API.

> **Warning:**
>
> The Notecard can only accept valid JSON in response to a `GET`, `POST`, or `PUT` request unless you override the default `content` argument of `application/json` with the appropriate MIME type.

```json
{
 "result": 200,
 "body": {
  "base": "stations",
  "clouds": {
   "all": 100
  },
  "cod": 200,
  "coord": {
   "lat": 42.7,
   "lon": -84.5
  },
  "dt": 1732291278,
  "id": 4991640,
  "main": {
   "feels_like": 274.45,
   "grnd_level": 976,
   "humidity": 90,
   "pressure": 1009,
   "sea_level": 1009,
   "temp": 278.52,
   "temp_max": 279.22,
   "temp_min": 277.77
  },
  "name": "East Lansing",
  "rain": {
   "1h": 0.25
  },
  "sys": {
   "country": "US",
   "id": 2030322,
   "sunrise": 1732279144,
   "sunset": 1732313392,
   "type": 2
  },
  "timezone": -18000,
  "visibility": 10000,
  "weather": [
   {
    "description": "light rain",
    "icon": "10d",
    "id": 500,
    "main": "Rain"
   }
  ],
  "wind": {
   "deg": 310,
   "speed": 6.17
  }
 }
}
```

Data returned by a proxy Route is delivered to the Notecard unmodified, by default.

> **Note:**
>
> Notehub limits the response it returns to the Notecard to a maximum of **8192 bytes**, whether that response is delivered in the `body` or the `payload` field. If the external service's response is larger than this, Notehub does not truncate it—instead it returns an error such as `response length (10936) is larger than max (8192) {too-big}`. Use an inbound JSONata transform (described below) to reduce the response to just the fields you need before Notecard receives it.

However, you can alter the data before it's sent using a JSONata expression in your route's **Inbound Response Transform** textarea. As an example refer to the JSONata expression shown in the image below.

![An example usage of an Inbound Response Transform in Notehub](https://dev.blues.io/images/notecard/walkthrough/web-transactions/inbound-jsonata.png?v=65915587)

This JSONata selects two fields out of the OpenWeatherMap API response—`main.temp` and `weather.main`—and exclusively includes them in the response. Line 2 of the JSONata also does some formatting on the temperature, converting it from Kelvin to Celsius, and rounding its value to two decimal points. (You can learn more about how JSONata works in [Using JSONata to Transform JSON](https://dev.blues.io/guides-and-tutorials/notecard-guides/using-jsonata-to-transform-json-in-notehub.md).)

When this JSONata expression is applied to the earlier OpenWeatherMap API response, it transforms the full JSON response into the following—greatly reducing the amount of data Notehub sends down to your device.

```json
{
  "result": 200,
  "body": {
    "status": "Rain",
    "temperature": 5.37
  }
}
```

> **Note:**
>
> Notecard only accepts JSON responses that are a single JSON object, e.g. `{"key":"value"}`. If your server instead returns an array of objects, e.g. `[{"key":"value"},{"key":"value2"}]`, you can use an inbound JSONata transform to change the structure of the response before Notecard receives it.
>
> For example, setting the **Inbound Response Transform** of a Notehub route to `{ "items": $ }` changes a response from `[{"key":"value"},{"key":"value2"}]` into `{"items":[{"key":"value"},{"key":"value2"}]}`, which Notecard will accept.

> **Note:**
>
> If you're using the Notecard's note-c or note-arduino [firmware libraries](https://dev.blues.io/tools-and-sdks/firmware-libraries.md), you can use the following pattern to parse values out of the returned JSON on your host microcontroller.
>
> ```c
> J *req = NoteNewRequest("web.get");
> if (req != NULL) {
>   JAddStringToObject(req, "route", "GetWeather");
>   J *rsp = NoteRequestResponse(req);
>   J *body = JGetObject(rsp, "body");
>   if (body != NULL) {
>     float temp = JGetNumber(body, "temperature");
>     const char *status = JGetString(body, "status");
>   }
>
>   NoteDeleteResponse(rsp);
> }
> ```

The Notecard does not store the result of web transactions in [Notes](https://dev.blues.io/api-reference/glossary.md#note). However, Notehub logs all web transactions as events, and you can view them in the Events view of your Notehub project.

![notehub proxy route event](https://dev.blues.io/images/reference/notecard-api/proxy-route-event.png?v=c5403d39)

If you double click an event and visit its **Route log** tab, you can view the result of your web transaction in the Notehub UI.

![notehub proxy route event details](https://dev.blues.io/images/reference/notecard-api/proxy-route-event-details.png?v=e8ec515f)

## Storing Web Transaction Responses in DB Notefiles

Notecard has the ability to perform a web transaction and then store the response in a [local-only Database Notefile](https://dev.blues.io/notecard/notecard-walkthrough/inbound-requests-and-shared-data.md#using-database-notefiles-for-local-only-state).

For example, if you issue a `web.get` request while Notecard is in `periodic` mode, it will immediately return `{"total":1}` (signifying there is one request pending). When Notecard next connects to Notehub, it will then perform any queued web transactions.

By default, Notecard discards the responses to these transactions, but you can have it store the responses in a local-only Database Notefile (`.dbx`) by passing the `file` and `note` arguments.

> **Note:**
>
> The `file` argument must reference a local-only Database Notefile—that is, its name must use the `.dbx` extension. Otherwise, the Notecard returns a `"response notefile must be of type dbx"` error.
>
> Also, be aware that passing the `file` argument always queues the web transaction for the Notecard's next connection to Notehub, even when the Notecard is in `continuous` mode and currently online.

**JSON**

```json
{
  "req": "web.get",
  "route": "GetForecast",
  "file": "weather.dbx",
  "note": "forecast"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("web.get");
JAddStringToObject(req, "route", "GetForecast");
JAddStringToObject(req, "file", "weather.dbx");
JAddStringToObject(req, "note", "forecast");

NoteRequest(req);
```

**Python**

```python
req = {"req": "web.get"}
req["route"] = "GetForecast"
req["file"] = "weather.dbx"
req["note"] = "forecast"

rsp = card.Transaction(req)
```

After the next connection with Notehub, the transaction should be complete and the response available in the specified Notefile.

**JSON**

```json
{
  "req": "note.get",
  "file": "weather.dbx",
  "note": "forecast"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.get");
JAddStringToObject(req, "file", "weather.dbx");
JAddStringToObject(req, "note", "forecast");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.get"}
req["file"] = "weather.dbx"
req["note"] = "forecast"

rsp = card.Transaction(req)
```

The stored Note's `body` contains a record of the completed transaction—not the web response alone. This record includes the HTTP status code of the transaction in a `result` field, and the web response itself in a nested `body` field.

The Notecard does not automatically remove stored responses from the Notefile. Once you have finished processing a response, add `"delete": true` to the `note.get` request to delete the stored Note.

## Sending Large Payloads to Notehub

Consult our guide on [Sending and Receiving Large Binary Objects](https://dev.blues.io/guides-and-tutorials/notecard-guides/sending-and-receiving-large-binary-objects.md) if your application needs to send large binary payloads to Notehub.

[Inbound Requests & Shared Data](https://dev.blues.io/notecard/notecard-walkthrough/inbound-requests-and-shared-data.md "Inbound Requests & Shared Data") [Low-Power Firmware Design](https://dev.blues.io/notecard/notecard-walkthrough/low-power-firmware-design.md "Low-Power Firmware Design")
