---
title: Inbound Requests & Shared Data
description: Learn how to initiate requests from a cloud-based application and send those requests to Blues Notecard using Notehub over Cellular, Satellite, LoRa, or WiFi connectivity
source_url: https://dev.blues.io/notecard/notecard-walkthrough/inbound-requests-and-shared-data/
canonical_url: https://dev.blues.io/notecard/notecard-walkthrough/inbound-requests-and-shared-data/
markdown_url: https://dev.blues.io/notecard/notecard-walkthrough/inbound-requests-and-shared-data.md
---

# Inbound Requests & Shared Data

All of the scenarios discussed so far in this guide are focused on performing requests directly against the Notecard from a host, and synching data from the Notecard to Notehub. This type of data is called "outbound data" because it is data that starts on the Notecard and is synchronized to Notehub. In other words it is "outbound" from the perspective of the Notecard.

Many solutions, however, will need to initiate data or requests from a cloud app or external service, and propagate that request down to the Notecard. This data is called "inbound data" because it is data that originates somewhere else and is synchronized to the Notecard. In other words, it is "inbound" from the perspective of the Notecard.

Using the API requests detailed below, you can perform inbound requests to:

- Share state between the Notecard and Notehub.
- Notify the host that new data is available.

Once available, a host can retrieve inbound data from the Notecard, and respond accordingly.

## Sending Data Through Notehub

Inbound requests are requests that originate somewhere other than the Notecard, and are sent to the Notecard from Notehub. These requests are created either directly in the Notehub UI or by using the [Notehub API](https://dev.blues.io/api-reference/notehub-api.md).

### Adding Inbound Notes in Notehub

To add a Note that will sync to the Notecard from the Notehub UI, navigate to the Devices dashboard, select your device, and click the "+ Note" button. In the modal, select the Notefile for your Note (the default is `data.qi`) and add the Note `body` as a JSON object.

> **Note:**
>
> This approach only supports adding inbound queue files with the `.qi` or `.qis` extensions. If you need to add Notes to a DB file, use the Notehub API, as described below.
>
> Also, inbound Notes MUST use [Note Templates](https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design.md#working-with-note-templates) (defined on the Notecard) if using with **Notecard LoRa** or NTN mode with **Starnote**.

![adding an inbound note with the notehub ui](https://dev.blues.io/images/reference/notehub-qi.png?v=2f301b9f)

### Adding Notes for Secure Transport

If you want to ensure that Notes are sent over encrypted TLS to the Notecard, use the `.qis` extension when specifying the Notefile. `.qis` signifies that the Notefile is a **secure inbound queue**.

![adding a secure inbound note with the notehub ui](https://dev.blues.io/images/reference/notehub-qis.png?v=25a69c4d)

### Adding Inbound Notes with the Notehub API

Alternatively, you may use the [Notehub API](https://dev.blues.io/api-reference/notehub-api.md) to add inbound notes to Notehub. This approach works for both `.qi`/`.qis` and `.db`/`.dbs` Notefiles.

For example, here's how to add a Note to the default `data.qi` file using curl. This is the [Add QI Note](https://dev.blues.io/api-reference/notehub-api/device-api.md#add-qi-note) endpoint, and the Notefile ID is the last path segment.

```bash
curl -X POST
    -L 'https://api.notefile.net/v1/projects/<projectUID>/devices/<deviceUID>/notes/data.qi'
    -H 'Authorization: Bearer <access_token>'
    -d '{"body":{"key-1":"val-1"}}'
```

> **Note:**
>
> Notehub API requests are authorized via Personal Access Tokens. Consult the [Notehub API documentation](https://dev.blues.io/api-reference/notehub-api.md) for more information.

Next, here’s an example for adding a new Note named `sync-settings` to a DB file named `my-settings.db`. DB Notes are addressed by both Notefile ID and Note ID, so the Note ID is appended to the path. This is the [Add DB Note](https://dev.blues.io/api-reference/notehub-api/device-api.md#add-db-note) endpoint, which creates the Notefile if it does not yet exist.

```bash
curl -X POST
    -L 'https://api.notefile.net/v1/projects/<projectUID>/devices/<deviceUID>/notes/my-settings.db/sync-settings'
    -H 'Authorization: Bearer <access_token>'
    -d '{"body": {"interval": 60 }}'
```

> **Note:**
>
> The request above *adds* a DB Note. To *update* an existing DB Note, use the [Update DB Note](https://dev.blues.io/api-reference/notehub-api/device-api.md#update-db-note) endpoint, which accepts a `PUT` on the same URL to replace the Note’s `body` and/or `payload`.

Notes added through Notehub are queued for the device and are only delivered on the Notecard's next inbound sync, which is governed by the `inbound` and `mode` arguments to [`hub.set`](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-set). A Notecard in `periodic` mode with `"inbound": 60`, for example, may take up to an hour to receive the Note. To have the Notecard pick it up inbound changes immediately, issue a [`hub.sync`](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-sync) request.

### Using Inbound Notefiles with Starnote

As a data-constrained satellite communication device, using NTN mode with Starnote requires the user to specifically request a check for inbound Notefiles from Notehub to minimize data usage. This is handled with the `"in":true` argument in the [hub.sync API](https://dev.blues.io/api-reference/notecard-api/hub-requests/latest.md#hub-sync):

```json
{
  "req": "hub.sync",
  "in": true
}
```

Also, as mentioned above, inbound Notefiles must use [Note Templates](https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design.md#working-with-note-templates) that are pre-defined on the Notecard when using NTN mode with Starnote.

## Handling Inbound Notes

After a successful sync, inbound Notes and Notefiles are available to your Notecard. To get an overview of new data across all of your files, use the `file.changes` request with no arguments.

**JSON**

```json
{
  "req": "file.changes"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("file.changes");

NoteRequest(req);
```

**Python**

```python
req = {"req": "file.changes"}

rsp = card.Transaction(req)
```

When passed with no arguments, `file.changes` returns an object with the total number of new notes across all files, and the totals for each file, by name.

```json
{
 "total": 3,
 "info": {
  "my-settings.db": {
   "total": 2
  },
  "data.qi": {
   "total": 1
  }
 }
}
```

To obtain a summary of changes across a subset of available files, use the `files` argument and an array containing the file or files you're interested in.

**JSON**

```json
{
  "req": "file.changes",
  "files": ["data.qi"]
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("file.changes");

J *files = JAddArrayToObject(req, "files");
JAddItemToArray(files, JCreateString("data.qi"));

NoteRequest(req);
```

**Python**

```python
req = {"req": "file.changes"}
req["files"] = ["data.qi"]

rsp = card.Transaction(req)
```

The response object is similar to the previous request, but returns only data for the files you specified.

```json
{
 "total": 1,
 "info": {
  "data.qi": {
   "total": 1
  }
 }
}
```

Once you've confirmed that inbound Notes are available, use the `note.get` request to retrieve them. Use the `file` argument to specify the name of the Notefile, or omit it to fetch a single Note from the `data.qi` Notefile.

**JSON**

```json
{
  "req": "note.get",
  "file": "requests.qi"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.get");
JAddStringToObject(req, "file", "requests.qi");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.get"}
req["file"] = "requests.qi"

rsp = card.Transaction(req)
```

Following queuing semantics, this request will return the *oldest* available Note in the `requests.qi` Notefile, and the time it was created in Notehub.

```json
{
 "body": {
  "api-key1": "api-val1"
 },
 "time": 1598909219
}
```

`note.get` does not, by default, remove a Note when you request it, so repeated calls will return the same Note, even if multiple Notes are available in the Notefile. To delete a Note after retrieval, use the `delete` argument. Subsequent requests will return and delete successive Notes in the Notefile.

**JSON**

```json
{
  "req": "note.get",
  "file": "requests.qi",
  "delete": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.get");
JAddStringToObject(req, "file", "requests.qi");
JAddBoolToObject(req, "delete", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.get"}
req["file"] = "requests.qi"
req["delete"] = True

rsp = card.Transaction(req)
```

When the queue is empty, `note.get` returns an error response containing the `{note-noexist}` tag, for example:

```json
{ "err": "no notes available {note-noexist}" }
```

## Using Database Files for Replicated State

Queued Notefiles (`.qo`, `.qos`, `.qi`, and `.qis`) are uni-directional in nature, and are not ideal for replicating state or settings between the Notecard and Notehub. For replicated state, use DB Notefiles. These files, which have a `.db` or `.dbs` extension, are synchronized between the Notecard and Notehub, and contain Notes that can be individually read and updated.

### Adding and Updating Notes in DB Notefiles

Add Notes to a DB file with the `note.add` request. In addition to a Notefile ID (`file`), adding Notes to a DB file requires a Note ID (`note`). The Note ID is used to manage the Note directly, because DB Notefiles hold shared state that is synchronized between the Notecard and Notehub.

**JSON**

```json
{
  "req": "note.add",
  "file": "my-settings.db",
  "note": "measurements",
  "body": {"interval": 10}
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.add");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "note", "measurements");

J *body = JCreateObject();
JAddNumberToObject(body, "interval", 10);
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.add"}
req["file"] = "my-settings.db"
req["note"] = "measurements"
req["body"] = {"interval": 10 }

rsp = card.Transaction(req)
```

> **Note:**
>
> `note.add` returns a `{note-exists}` error if a Note with the provided ID already exists in the Notefile. To have Notecard generate a unique Note ID for you, pass `"note": "?"`, and the generated ID is returned in the response.

As with other `note.add` requests, a `payload` can be provided instead of, or in addition to, a `body`.

**JSON**

```json
{
  "req": "note.add",
  "file": "my-settings.db",
  "note": "measurements",
  "payload": "ewogICAgInRlbXAiOiAyMy4xMzQKfQ=="
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.add");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "note", "measurements");
JAddStringToObject(req, "payload", "ewogICAgInRlbXAiOiAyMy4xMzQKfQ==");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.add"}
req["file"] = "my-settings.db"
req["note"] = "measurements"
req["payload"] = "ewogICAgInRlbXAiOiAyMy4xMzQKfQ=="

rsp = card.Transaction(req)
```

To update a Note in a DB Notefile, use the `note.update` request. Provide a new `body` or `payload` to replace the existing Note content. If the specified Note (or the Notefile itself) does not exist, `note.update` creates it.

The `note.update` request replaces the entire body rather than performing a partial merge; therefore, any fields not included in the new body will be removed.

**JSON**

```json
{
  "req": "note.update",
  "file": "my-settings.db",
  "note": "measurements",
  "body": {"interval": 60 }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.update");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "note", "measurements");

J *body = JCreateObject();
JAddNumberToObject(body, "interval", 60);
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.update"}
req["file"] = "my-settings.db"
req["note"] = "measurements"
req["body"] = {"interval": 60 }

card.Transaction(req)
```

A successful `note.update` returns an empty JSON object (`{}`).

### Simplifying DB Notefiles with the var API

For the common case of storing simple named values — a numeric setting, a string, a boolean switch — the [`var` requests](https://dev.blues.io/api-reference/notecard-api/var-requests/latest.md) provide a simpler interface over DB Notefiles. `var.set`, `var.get`, and `var.delete` are shorthand for `note.update`, `note.get`, and `note.delete`, where the variable's `name` is the Note ID, and the value is provided in a typed argument: `text` for strings, `value` for numbers, or `flag` for booleans. Variables are stored in a DB Notefile named `vars.db` by default (this is configurable with the `file` argument), and are replicated to and from Notehub like any other DB Notefile content.

**JSON**

```json
{
  "req": "var.set",
  "name": "interval",
  "value": 60
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("var.set");
JAddStringToObject(req, "name", "interval");
JAddNumberToObject(req, "value", 60);

NoteRequest(req);
```

**Python**

```python
req = {"req": "var.set"}
req["name"] = "interval"
req["value"] = 60

card.Transaction(req)
```

**JSON**

```json
{
  "req": "var.get",
  "name": "interval"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("var.get");
JAddStringToObject(req, "name", "interval");

NoteRequest(req);
```

**Python**

```python
req = {"req": "var.get"}
req["name"] = "interval"

rsp = card.Transaction(req)
```

For a complete walkthrough of using the `var` requests to manage device state, see [Storing Device State with DB Notefiles](https://dev.blues.io/guides-and-tutorials/notecard-guides/storing-device-state-with-db-notefiles.md).

### Fetching Notes from DB Notefiles

To retrieve a Note from a DB Notefile, use the `note.get` request and provide the `file` and `note` arguments with the Notefile ID and Note ID, respectively.

**JSON**

```json
{
  "req": "note.get",
  "file": "my-settings.db",
  "note": "measurements"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.get");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "note", "measurements");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.get"}
req["file"] = "my-settings.db"
req["note"] = "measurements"

rsp = card.Transaction(req)
```

The request above will return the `measurements` Note in the `my-settings.db` Notefile and the time of creation or the most recent update (shown below).

```json
{
 "note": "measurements",
 "body": {
  "interval": 60
 },
 "time": 1598916085
}
```

### Deleting Notes from a DB Notefile

To delete a DB Note after retrieval, use the `delete` argument.

**JSON**

```json
{
  "req": "note.get",
  "file": "my-settings.db",
  "note": "measurements",
  "delete": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.get");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "note", "measurements");
JAddBoolToObject(req, "delete", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.get"}
req["file"] = "my-settings.db"
req["note"] = "measurements"
req["delete"] = True

rsp = card.Transaction(req)
```

Alternatively, if you do not need to retrieve the Note, delete the Note with the `note.delete` request. If successful, this request will return an empty JSON object (`{}`).

**JSON**

```json
{
  "req": "note.delete",
  "file": "my-settings.db",
  "note": "measurements"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.delete");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "note", "measurements");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.delete"}
req["file"] = "my-settings.db"
req["note"] = "measurements"

card.Transaction(req)
```

Because DB Notefiles are shared between the Notecard and Notehub, updates and deletions made by either are reconciled during each sync.

### Using Database Notefiles for Local-Only State

Sometimes, your host may wish to use the Notecard to store application state or configuration, but you **do not** want that state to be synchronized to Notehub. For these cases, you can use the `.dbx` extension to create a Local-only Notefile. The semantics for adding, updating, and deleting local-only Database Notefiles is the same as detailed above for replicated Database files — including the `var` requests, which work with a `.dbx` Notefile when passed a `file` argument.

Notes in a `.dbx` Notefile persist across restarts of both the host and the Notecard, which makes a `.dbx` Notefile useful as a small persistent key-value store for hosts with limited non-volatile storage of their own. Because these files never sync, changes to them never trigger outbound syncs or consume bandwidth, and `.dbx` Notefiles never appear in Notehub (including in the [Notefile explorer](https://dev.blues.io/notehub/notehub-walkthrough.md#managing-notefiles)).

**JSON**

```json
{
  "req": "note.add",
  "file": "local-config.dbx",
  "note": "sensor-types",
  "body": {"temp": "si7201", "gas": "bme680"}
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.add");
JAddStringToObject(req, "file", "local-config.dbx");
JAddStringToObject(req, "note", "sensor-types");

J *body = JCreateObject();
JAddStringToObject(body, "temp", "si7201");
JAddStringToObject(body, "gas", "bme680");
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.add"}
req["file"] = "local-config.dbx"
req["note"] = "sensor-types"
req["body"] = {"temp": "si7201", "gas": "bme680"}

rsp = card.Transaction(req)
```

## Using Change Trackers with Inbound Data

If your host needs to work with inbound data on a regular basis within and across Notefiles, you can use a change tracker to incrementally work with inbound data. A change tracker is identified by a developer-defined string, like `my_inbound_requests`, and used to associate additions and deletions to Notefiles.

> **Note:**
>
> Change trackers are associated with their respective files. Once a change tracker is created, it will consume resources until the changes have been queried. As a result, change trackers should not be created without a plan to consume the accumulated changes, and should be removed when no longer needed.

> **Warning:**
>
> Change trackers are not supported on Notecard for LoRa.

### Configuring a Change Tracker for a Notefile

To set up a change tracker for a single file, use the `note.changes` request with the Notefile ID as `file`, and a change tracker ID in the `tracker` argument.

**JSON**

```json
{
  "req": "note.changes",
  "file": "my-settings.db",
  "tracker": "my_inbound_requests"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.changes");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "tracker", "my_inbound_requests");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.changes"}
req["file"] = "my-settings.db"
req["tracker"] = "my_inbound_requests"

rsp = card.Transaction(req)
```

This request returns an object with the total number of Notes in the Notefile, the total number of Notes changed since the change tracker was started, and an object containing each Note body, organized by ID.

```json
{
  "changes": 4,
  "total": 4,
  "notes": {
    "setting-one": { "body": { "foo": "bar" }, "time": 1598918235 },
    "setting-two": { "body": { "foo": "bat" }, "time": 1598918245 },
    "setting-three": { "body": { "foo": "baz" }, "time": 1598918225 },
    "setting-four": { "body": { "foo": "foo" }, "time": 1598910532 }
  }
}
```

On the first call, a tracker is instantiated, and the inbound tracker lists all existing Notes in a Notefile. When a tracker is instantiated, the state changes from zero Notes being tracked, to all the Notes in a Notefile being tracked. As a result, the list of changes, or all Notes, are displayed.

**Change trackers on inbound queue Notefiles (.qi/.qis)**

Using a change tracker on an inbound queue `.qi/.qis` is not recommended.

Notes in queues are expected to be consumed completely, making change trackers unnecessary. When used in such a manner, you may perform a `note.get` to check whether the queue is empty to detect if a change has occurred.

If you find you need long-lived data and your usage pattern does not align with the pattern outlined above, then your application may be better suited for use with a DB Notefile or [environment variables](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md).

However, if you elect to use a change tracker with `.qi/.qis` Notefiles, then be aware the [Note ID](https://dev.blues.io/api-reference/glossary.md#note-id) is a system-generated, internal ID. Whereas in DB Notefiles, the Note ID is developer-specified.

**`.qi`/`.qis` Tracker Response Example:**

```json
{
 "changes": 1,
 "total": 1,
 "notes": {
  "1:495": {...}
 }
}
```

Continuing with the example above, assume three more settings have been added to the DB Notefile, `my-settings.db`.

Use the `max` argument to limit the number of notes returned when querying a change tracker.

**JSON**

```json
{
  "req": "note.changes",
  "file": "my-settings.db",
  "tracker": "my_inbound_requests",
  "max": 2
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.changes");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "tracker", "my_inbound_requests");
JAddNumberToObject(req, "max", 2);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.changes"}
req["file"] = "my-settings.db"
req["tracker"] = "my_inbound_requests"
req["max"] = 2

rsp = card.Transaction(req)
```

Subsequent calls to `note.changes` will display changed files only, while hiding previously viewed changes.

```json
// First Request
{
  "changes": 3,
  "total":   7,
  "notes":   {
    "setting-five": {"body":{"bim": "bam"},"time":1598912838},
    "setting-six": {"body":{"bing": "bong"},"time":1598923484}
  }
}

// Second Request
{
  "changes": 1,
  "total":   7,
  "notes":   {
    "setting-seven": {"body":{"zip": "zap"},"time":1598927365}
  }
}

// Third Request
{"total":7}
```

Notes will be retrieved incrementally until all Notes are returned, at which point an object with only the `total` field is returned.

By default, Notes returned in `note.changes` are not deleted. If you want to delete them from the Notefile set the `delete` argument to `true`.

**JSON**

```json
{
  "req": "note.changes",
  "file": "my-settings.db",
  "tracker": "my_inbound_requests",
  "delete": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.changes");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "tracker", "my_inbound_requests");
JAddBoolToObject(req, "delete", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.changes"}
req["file"] = "my-settings.db"
req["tracker"] = "my_inbound_requests"
req["delete"] = True

rsp = card.Transaction(req)
```

> **Note:**
>
> To include deleted Notes in the response, set the `deleted` argument to `true`. Deleted Notes are only retained in a database Notefile (`.db`/`.dbs`) between the time a Note is deleted on the Notecard and the next sync with Notehub, so `deleted` has no effect after a sync or on queue Notefiles (`.q*`).

### Resetting a Change Tracker

If changes need to be reprocessed for any given reason, the `reset` parameter allows you to reset the change counter and tracker to their original states.

To reset a change tracker, perform a request to `note.changes` with the Notefile and change tracker id, and set the `reset` argument to `true`.

**JSON**

```json
{
  "req": "note.changes",
  "file": "my-settings.db",
  "tracker": "my_inbound_requests",
  "reset": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.changes");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "tracker", "my_inbound_requests");
JAddBoolToObject(req, "reset", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.changes"}
req["file"] = "my-settings.db"
req["tracker"] = "my_inbound_requests"
req["reset"] = True

rsp = card.Transaction(req)
```

### Deleting a Change Tracker

Change trackers are meant to be long-lived and enable you to easily scan for changes on the Notecard at any time. As such, you won't often need to delete a change tracker unless the needs of your application change.

To delete a change tracker, perform a request to `note.changes` with the Notefile and change tracker id, and set the `stop` argument to `true`.

**JSON**

```json
{
  "req": "note.changes",
  "file": "my-settings.db",
  "tracker": "my_inbound_requests",
  "stop": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.changes");
JAddStringToObject(req, "file", "my-settings.db");
JAddStringToObject(req, "tracker", "my_inbound_requests");
JAddBoolToObject(req, "stop", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.changes"}
req["file"] = "my-settings.db"
req["tracker"] = "my_inbound_requests"
req["stop"] = True

rsp = card.Transaction(req)
```

### Using Change Trackers Across Multiple Notefiles

To use a change tracker with multiple files, use the `tracker` argument with the `file.changes` request, and provide a list of files to track.

Analogous to `note.changes`, the first request will create trackers of the same name on each of the Notefiles listed, and each subsequent request will query those existing trackers and return the results as a single response.

**JSON**

```json
{
  "req": "file.changes",
  "tracker": "multi-file-tracker",
  "files": ["my-settings.db", "other-settings.db"]
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("file.changes");
JAddStringToObject(req, "tracker", "multi-file-tracker");

J *files = JAddArrayToObject(req, "files");
JAddItemToArray(files, JCreateString("my-settings.db"));
JAddItemToArray(files, JCreateString("other-settings.db"));

NoteRequest(req);
```

**Python**

```python
req = {"req": "file.changes"}
req["tracker"] = "multi-file-tracker"
req["files"] = ["my-settings.db", "other-settings.db"]

rsp = card.Transaction(req)
```

The response returns the number of changes per file, as well as the total changes across all files.

```json
{
  "changes": 5,
  "total": 5,
  "info": {
    "my-settings.db": { "changes": 3, "total": 3 },
    "other-settings.db": { "changes": 2, "total": 2 }
  }
}
```

Using the `file.changes` tracker syntax provides an efficient way to quickly query several files and determine which files have changed. Once the changed files are known, you can process those individual Notefiles using the `note.changes` API outlined above.

## Handling Notecard Interrupts

Host applications that interface with the Notecard often need to determine if the Notecard has received inbound data for the host to process. This can be achieved through periodic polling and the use of change trackers, as described in [Using Change Trackers with Inbound Data](#using-change-trackers-with-inbound-data). However, this approach can be power-intensive on the host and difficult to optimize for low-power applications. As such, the Notecard exposes a hardware pin called `ATTN` (referred to as the "attention pin"), which is used to notify the host that the Notecard has detected an event of interest. The `card.attn` request is used to configure the behavior of the `ATTN` pin.

Depending upon its configuration, the Notecard can notify the host MCU in one or more of the following scenarios:

- When the Notecard receives a Note in specified Notefiles.
- When the Notecard connects to Notehub.
- When the Notecard detects motion.
- When the Notecard detects a location change.
- When the Notecard detects a change to its network state.
- When the Notecard is configured as a Watchdog timer.

### Interrupt behavior

Arming the interrupt causes the Notecard to pull the `ATTN` pin `LOW`. When armed, the GPIO connected to the Notecard attention pin will also read `LOW`, unless one of the monitored events occurs, in which case the pin will read `HIGH`. The interrupt is a *latching* interrupt. This means once it is armed, it will stay `LOW` until it has been disarmed or fired, and conversely, once fired it will remain `HIGH` until it has been rearmed.

> **Note:**
>
> In order to take full advantage of this behavior, you must correctly configure your host microcontroller. The two most common configurations are attaching the Notecard's `ATTN` pin to an interrupt capable GPIO pin or to the chip enable (`EN`) pin on the host MCU. In either case, your host MCU should respond by obtaining inbound file changes, rearming the interrupt, or performing other application specific actions.

### Configuring the Attention Pin

In a `card.attn` request, the `mode` argument is the primary interface for configuring the attention configurations described below. In addition, this argument is used to arm and disarm the attention pin, `ATTN`. The `mode` argument accepts both single arguments, and a comma-separated list of keywords that enable the configurations described below.

#### Disarming the Attention Pin

To disarm the pin, pass `disarm` into the `mode` argument. Disarming the attention pin pulls the pin `HIGH`.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "disarm"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "disarm");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "disarm"

card.Transaction(req)
```

As of Notecard firmware *v3.2.1*, if you have multiple attention modes configured as detailed below, you can disarm all of these at once with the `-all` flag.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "disarm,-all"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "disarm,-all");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "disarm,-all"

card.Transaction(req)
```

#### Arming the Attention Pin

To arm the attention pin, pass `arm` into the `mode` argument of a `card.attn` request, along with the optional keywords or parameters that correspond with your desired configuration.

##### Setting an Attention Timeout

The simplest attention mode configuration is to arm the pin, and instruct the Notecard to bring the pin `HIGH` after a timeout of `n` seconds. You can do this with the `seconds` argument, and by setting `mode` to `arm`.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm",
  "seconds": 10
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm");
JAddNumberToObject(req, "seconds", 10);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm"
req["seconds"] = 10

card.Transaction(req)
```

This request will return an empty JSON object (`{}`). Then, after the timeout has elapsed, the attention pin will be pulled `HIGH` by the Notecard. You can confirm that the attention pin has fired by making a request to `card.attn` with no arguments.

**JSON**

```json
{
  "req": "card.attn"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}

card.Transaction(req)
```

This request will return an object with a boolean, `set`, reflecting the state of the `ATTN` pin and a `files` array. The `files` array contains the `timeout` keyword, reflecting a timeout has occurred.

```json
{
  "files": ["timeout"],
  "set": true
}
```

If the attention pin has not fired, a request to `card.attn` will return an empty JSON object (`{}`).

> **Note:**
>
> The `files` parameter is used as an input/output parameter with a list of files to watch for changes, and also to receive a list of Notefile IDs that have changed when using `files` mode.

#### Watching for File Changes

If you want your host to be notified when the Notecard detects file changes, use `files` in the `mode` argument, as well as the `files` argument to provide an array of one or more Notefiles to watch.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,files",
  "files": ["data.qi", "my-settings.db"]
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,files");

J *files = JAddArrayToObject(req, "files");
JAddItemToArray(files, JCreateString("data.qi"));
JAddItemToArray(files, JCreateString("my-settings.db"));

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,files"
req["files"] = ["data.qi", "my-settings.db"]

card.Transaction(req)
```

Alternatively, pass an empty string array to the `files` argument to watch all Notefiles on the Notecard.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,files",
  "files": [""]
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,files");

J *files = JAddArrayToObject(req, "files");
JAddItemToArray(files, JCreateString(""));

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,files"
req["files"] = [""]

card.Transaction(req)
```

The interrupt fires when the Notecard detects a change to a watched file. You can use a no argument `card.attn` request to determine which file has changed. The response object will contain the name of the modified file, so you can issue a `note.changes` request to get new or modified Notes.

```json
{
  "files": ["data.qi", "modified"],
  "set": true
}
```

To disable file mode, issue another `card.attn` request, and add a dash before the `files` string in the `mode` argument to indicate that it should be disabled.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "-files"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "-files");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "-files"

card.Transaction(req)
```

#### Watching for Service Connections

The attention pin can be set to fire whenever the Notecard successfully connects to Notehub with the `connected` string in the `mode` argument.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,connected"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,connected");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,connected"

card.Transaction(req)
```

The interrupt fires the next time the Notecard connects. You can use a no argument, `card.attn` request to confirm the reason. In connection mode, the `files` array in a `card.attn` response object will include the `connected` string.

```json
{
  "files": ["connected"],
  "set": true
}
```

To disable connection mode, issue another `card.attn` request, and add a dash before the `connected` string in the `mode` argument to indicate that it should be disabled.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "-connected"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "-connected");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "-connected"

card.Transaction(req)
```

#### Watching for Notecard Motion

The attention pin can be set to fire whenever the Notecard accelerometer detects motion with the `motion` string in the `mode` argument.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,motion"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,motion");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,motion"

card.Transaction(req)
```

The interrupt fires when the accelerometer detects movement. You can use a no argument `card.attn` request to confirm the reason. In motion mode, the `files` array in a `card.attn` response object will include the `motion` string.

```json
{
  "files": ["motion"],
  "set": true
}
```

To disable motion mode, issue another `card.attn` request, and add a dash before the `motion` string in the `mode` argument to indicate that it should be disabled.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "-motion"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "-motion");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "-motion"

card.Transaction(req)
```

#### Watching for Notecard Location Updates

The attention pin can be set to fire whenever the Notecard GPS/GNSS module detects a location update with the `location` string in the `mode` argument.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,location"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,location");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,location"

card.Transaction(req)
```

The interrupt fires when a location change is detected. You can use a no argument `card.attn` request to confirm the reason. In location mode, the `files` array in a `card.attn` response object will include the `location` string.

```json
{
  "files": ["location"],
  "set": true
}
```

To disable location mode, issue another `card.attn` request, and add a dash before the `location` string in the `mode` argument to indicate that it should be disabled.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "-location"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "-location");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "-location"

card.Transaction(req)
```

#### Watching for Environment Variable Changes

The attention pin can be set to fire whenever the Notecard detects an Environment Variable update with the `env` string in the `mode` argument.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,env"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,env");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,env"

card.Transaction(req)
```

The interrupt fires when an Environment Variable change is detected. You can use a no argument `card.attn` request to confirm the reason. In env mode, the `files` array in a `card.attn` response object will include the `env` string.

```json
{
  "files": ["env"],
  "set": true
}
```

To disable env mode, issue another `card.attn` request, and add a dash before the `env` string in the `mode` argument to indicate that it should be disabled.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "-env"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "-env");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "-env"

card.Transaction(req)
```

#### Watching for Notecard Network Status Changes

The attention pin can be set to fire whenever the Notecard detects a change in the network status it communicates via the `card.wireless` request.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,wireless"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,wireless");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,wireless"

card.Transaction(req)
```

The interrupt fires when a network status change is detected. You can use a no argument [`card.wireless` request](https://dev.blues.io/api-reference/notecard-api/card-requests.md#card-wireless) to inspect the change. In wireless mode, the `files` array in a `card.attn` response object will include the `wireless` string.

```json
{
  "files": ["wireless"],
  "set": true
}
```

To disable wireless mode, issue another `card.attn` request, and add a dash before the `wireless` string in the `mode` argument to indicate that it should be disabled.

**JSON**

```json
{
  "req": "card.attn",
  "mode": "-wireless"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "-wireless");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "-wireless"

card.Transaction(req)
```

#### Using Multiple Modes Together

The modes described above are not mutually-exclusive, and can be used together. Simply provide a comma between each watch mode when calling `card.attn`:

**JSON**

```json
{
  "req": "card.attn",
  "mode": "arm,files,connected,location",
  "files": ["data.qi"]
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.attn");
JAddStringToObject(req, "mode", "arm,files,connected,location");

J *files = JAddArrayToObject(req, "files");
JAddItemToArray(files, JCreateString("data.qi"));

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.attn"}
req["mode"] = "arm,files,connected,location"
req["files"] = ["data.qi"]

card.Transaction(req)
```

When multiple modes are used together, no argument calls to `card.attn` will identify all of the modes and files that caused the pin to fire.

```json
{
  "files": ["data.qi", "motion", "connected"],
  "set": true
}
```

## Miscellaneous File Requests

To obtain information about local Notefiles on the Notecard, use the `file.stats` request.

```json
{
  "req": "file.stats"
}
```

This request returns a total number of Notes across all Notefiles, a count of the number of Notes pending sync to Notehub (`changes`), if any, and a `sync` field of `true` if a sync is recommended based on the number of pending Notes. This field should be considered `false` if not present.

```json
{
 "changes": 1,
 "total": 4
}
```

To scope the statistics to a single Notefile, provide the Notefile's name in the optional `file` argument.

```json
{
 "req": "file.stats",
 "file": "sensors.qo"
}
```

For details on Notes pending sync, use the `file.changes.pending` request.

```json
{
  "req": "file.changes.pending"
}
```

This request returns a `pending` boolean indicating whether any Notes are pending sync, total notes and changes across all files, as well as a per-file listing of pending changes.

```json
{
 "changes": 2,
 "total": 2,
 "pending": true,
 "info": {
  "sensors.qo": {
   "changes": 1,
   "total": 1
  },
  "data.qo": {
   "changes": 1,
   "total": 1
  }
 }
}
```

Finally, to delete a Notefile and all of the Notes contained within, use the `file.delete` request. This request accepts a single argument `files`, which is an array of Notefiles to delete. If successful, this request will return an empty JSON object (`{}`).

```json
{
 "req": "file.delete",
 "files": [
  "sensors.qo"
 ]
}
```

For complete details on these requests and their arguments, see the [file Requests API reference](https://dev.blues.io/api-reference/notecard-api/file-requests.md).

[Time & Location Requests](https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests.md "Time & Location Requests") [Web Transactions](https://dev.blues.io/notecard/notecard-walkthrough/web-transactions.md "Web Transactions")
