# StreamZet xSpan SDK 0.2.1

Documentation revision: 2026-09-21

https://streamzet.com/docs

## StreamZet developer docs

Connect your devices and integrate remote support into your product. Install and integrate the xSpan SDK 0.2.1.

### Choose your starting point

- [Test on a reader first](https://streamzet.com/docs/xspan/quickstart)
- [Integrate with a C/C++ product](https://streamzet.com/docs/xspan/integration)
- [Review delivery packages and checksums](https://streamzet.com/docs/xspan/packages)

Use the prebuilt engine for an installation test. Ship the C adapter and the same engine for product integration. Both modes use persistent per-device state; do not run both against the same state at once.

### xSpan capabilities

| Capability | Current scope |
| --- | --- |
| Auto enrollment | Automatically appears in the account’s Devices after initial enrollment; requires connectivity. |
| Remote terminal | Interactive sh terminal in the browser, running with the installed agent’s OS privileges. |
| Fleet commands | Select multiple or all eligible online readers; inspect status, stdout, stderr and exit code per device. |
| RFID dashboard | Open the original OEM dashboard after per-device certificate provisioning. Existing OEM login is required. |

### Compatibility and qualification

| Item | Verified environment |
| --- | --- |
| Reader | Impinj xSpan R660 |
| CPU / ABI | ARMv5TE · soft-float · static musl engine |
| Linux / OEM libc | 2.6.39.4 / glibc 2.19 |
| Octane firmware | 6.2.2.240 |
| OEM application | RFID Overhead 360° 2.22.11.30 |
| SDK / documentation | 0.2.1 / 2026-09-21 |

> Enrollment, terminal, Fleet commands, SDK lifecycle and the web dashboard were verified on one physical R660. Other models/firmware, a full reboot and multi-reader hardware load require separate acceptance tests.

### Other platforms

Commands and binaries in this guide target xSpan. Android AAR/test APKs and the modern Linux SDK preview are separate artifacts. Android screen sharing requires consent; physical HHT acceptance, signed distribution and target Linux ABI qualification are separate steps.

> Use the POSIX process adapter for an existing glibc application. Directly linking the musl static libraries into that glibc application is not qualified.

## Quickstart: test a reader

Prepare a unique installation directory on a trusted computer, install it on one xSpan, and verify the connection.

### 1. Prerequisites

- An xSpan R660 matching the qualified environment, with authorized SSH or OEM factory provisioning access.
- The evaluation ZIP, a separately supplied enrollment key file and a StreamZet operator account.
- Python 3 on the provisioning computer; correct reader time, DNS and outbound TCP 443. Python is not required on the reader.

> Paths and READER_HOST below are examples. Use reader-001 for exactly one reader. Do not overwrite an existing installation’s state using this first-install procedure.

### 2. Extract and verify

```sh
shasum -a 256 -c streamzet-xspan-evaluation-0.2.1-20260921.zip.sha256
unzip streamzet-xspan-evaluation-0.2.1-20260921.zip -d xspan-evaluation
cd xspan-evaluation
shasum -a 256 -c SHA256SUMS
```

On Linux, sha256sum -c can replace shasum. Obtain the checksum file together with the ZIP.

### 3. Provision one device

```sh
umask 077
mkdir -p ./provisioning
python3 device/prepare-device.py \
  --registration-key /secure/JCI-production-key.txt \
  --output ./provisioning/reader-001 \
  --name 'xSpan R660 001'
```

The new directory contains the engine, CA bundle, lifecycle scripts, enrollment key and a unique 64-byte entropy seed. The tool refuses an existing output directory. First startup creates state/identity containing the device UUID and secret.

### 4. Transfer and start

Use verified SSH or approved factory provisioning. This example assumes /mnt/spp/streamzet-jci does not already exist on the test reader. Adapt the installation location to the OEM’s persistent-storage policy.

```sh
# On the provisioning computer
scp -pr ./provisioning/reader-001 root@READER_HOST:/mnt/spp/streamzet-jci

# In the reader's authorized shell
cd /mnt/spp/streamzet-jci
chmod 700 . state streamzet-embedded start.sh stop.sh
chmod 600 registration.key cacert.pem device-name state/entropy.seed
./start.sh
```

> Do not pass passwords or enrollment key values as command-line arguments. Never clone an enrolled device’s state directory to another reader.

### 5. Verify the connection

1. Sign in to StreamZet and confirm that the named reader appears online in Devices.
2. Open the terminal and run the read-only commands below. The output should match the actual reader.
3. In Fleet → Linux → sh · xSpan / embedded, select only this test reader and run the same command. Check its result and exit code.

```sh
printf 'STREAMZET_TEST_OK\n'
uname -m
uptime
```

The agent checks the Fleet queue approximately every 30 seconds. Enrollment is asynchronous; successful process startup does not by itself confirm online status.

- [Configure startup and operations](https://streamzet.com/docs/xspan/operations)
- [Troubleshoot a missing reader](https://streamzet.com/docs/xspan/troubleshooting)

## C/C++ integration

Connect remote support to your product lifecycle. Use the POSIX process adapter for existing glibc applications.

### Integration architecture

```text
OEM application (your ETK / libc)
  └─ streamzet_product.c  [start / poll / stop]
       └─ streamzet-embedded  [static ARMv5 engine]
            └─ outbound TLS :443 → StreamZet
                 └─ enrollment · terminal · Fleet · dashboard
```

Compile the small C adapter into the OEM application and ship the qualified static engine alongside it. TLS and the C runtime remain in a separate process. The engine handles transport, enrollment and network reconnect; the host starts, monitors and stops the child.

### Required files

| File | Purpose |
| --- | --- |
| sdk/product/streamzet_product.h | Public C/C++ interface |
| sdk/product/streamzet_product.c | POSIX adapter compiled with the OEM ETK |
| sdk/product/example.c | Start, monitor, stop and reap example |
| device/streamzet-embedded | Qualified static ARMv5 engine |
| device/cacert.pem | CA bundle for server authentication |
| registration.key + state/ | Provisioned and preserved per device |

### Compile with your product toolchain

```sh
# Set CC to the matching OEM ETK C compiler.
"$CC" -std=c99 -D_POSIX_C_SOURCE=200809L \
  -Isdk/product sdk/product/example.c sdk/product/streamzet_product.c \
  -o streamzet-product-example
```

For C++, compile streamzet_product.c as C, link that object, and include the header. Copy the resulting example to the provisioned reader and run it below. Stop an existing start.sh-managed engine and wait for its full exit before reusing its state.

```sh
./streamzet-product-example \
  /mnt/spp/streamzet-jci/streamzet-embedded \
  /mnt/spp/streamzet-jci/registration.key \
  /mnt/spp/streamzet-jci/cacert.pem \
  /mnt/spp/streamzet-jci/state \
  'xSpan R660 001'
```

### Host lifecycle example

```c
#include "streamzet_product.h"

static stz_product support = {0};

int start_remote_support(void) {
    const stz_product_config config = {
        .engine_path = "/mnt/spp/streamzet-jci/streamzet-embedded",
        .registration_file = "/mnt/spp/streamzet-jci/registration.key",
        .ca_file = "/mnt/spp/streamzet-jci/cacert.pem",
        .state_directory = "/mnt/spp/streamzet-jci/state",
        .device_name = "xSpan R660 001"
    };
    return stz_product_start(&support, &config);
}

/* Call periodically from the same host thread. */
int poll_remote_support(int *wait_status) {
    return stz_product_poll(&support, wait_status);
}

/* Request stop, then keep polling until the child is reaped. */
int stop_remote_support(void) {
    return stz_product_stop(&support);
}
```

- A zero start return value confirms spawn success. Confirm online status in StreamZet.
- Serialize calls on a handle. Do not let another SIGCHLD handler reap this child.
- Mark unrelated host file descriptors close-on-exec. The adapter child inherits stdout/stderr.
- Network reconnect is automatic. Detect process exits through poll and apply the OEM restart policy.
- Do not run start.sh alongside SDK mode. After a stop request, reap via poll before reusing the handle.

- [Fields, return values and errors](https://streamzet.com/docs/xspan/api)

### Low-level static library

sdk/musl contains libstreamzet-embedded.a, TLS archives and headers. A new musl ARMv5 application uses stz_create → stz_run on a worker thread → stz_stop → join → stz_destroy, with the documented entropy, persistent identity and single TLS-runtime contracts.

> This is not a drop-in library for an existing glibc app. Direct in-process integration requires the matching ETK, ABI, threading and TLS qualification. Use the process adapter for the initial partner integration.

## C API reference

The public contract in streamzet_product.h. This API controls the engine lifecycle.

### stz_product_config

| Field | Type and requirement |
| --- | --- |
| engine_path | const char* · Absolute engine path |
| registration_file | const char* · Absolute path to an owner-only enrollment key file (0600). |
| ca_file | const char* · Absolute CA PEM path |
| state_directory | const char* · Absolute per-device persistent directory path (0700). |
| device_name | const char* · Nonempty UTF-8 name, at most 128 bytes |

Paths must be shorter than 1,024 bytes. Keep string pointers valid until start returns. The provisioning tool rejects control characters in names. Initialize the stz_product handle to {0}; do not copy it to share ownership.

### stz_product_start

```c
int stz_product_start(stz_product *product,
                      const stz_product_config *config);
```

| Return | Meaning |
| --- | --- |
| 0 | Child spawned. Enrollment and network connection proceed asynchronously. |
| EINVAL | Invalid argument, relative/oversized path, or device name |
| EALREADY | This handle already owns a running child |
| ECHILD | Could not inspect/reap the previous child |
| ENOENT / EACCES / other errno | posix_spawn or setup failure. Interpret the return value as an errno code. |

File-content and network-configuration errors can occur after spawn and cause the engine to exit. Keep polling after a successful start.

### stz_product_poll

```c
int stz_product_poll(stz_product *product, int *wait_status);
```

| Return | Meaning |
| --- | --- |
| 1 | Child is still running; nonblocking. |
| 0 | Already stopped, or exited and reaped. The handle PID is reset to zero. |
| -1 | NULL handle or waitpid error |

wait_status may be NULL. When this call reaps a child, inspect the status with WIFEXITED/WEXITSTATUS or WIFSIGNALED/WTERMSIG from sys/wait.h. An already-stopped handle does not write a new exit status.

### stz_product_stop

```c
int stz_product_stop(stz_product *product);
```

Requests SIGTERM if running. Returns zero on success or when already stopped; EINVAL for a NULL handle, ECHILD for a child-state error, or errno for signal delivery failure. This function does not wait for shutdown; reap the child with poll.

### Threading and state ownership

Serialize all calls on a handle using one thread or external locking. The adapter passes credential file paths rather than key values, without evaluating arguments through a shell. The engine’s file lock rejects concurrent use of the same state directory.

## Operations and Fleet

Configure startup, remote access, per-reader dashboard access and updates that preserve identity.

### Start on boot

For a standalone installation, add the StreamZet start.sh call to /cust/start on the qualified R660. Preserve OEM lines and back up the original. In SDK mode the product calls stz_product_start, so a separate start.sh boot hook is unnecessary.

```sh
# Standalone mode: add once to the OEM-approved startup hook
/mnt/spp/streamzet-jci/start.sh
```

> Do not re-run the entire /cust/start on a live reader; that can start the RFID application again. OEM CAP/firmware updates may replace the hook. Include it in the OEM product package and perform reboot acceptance testing.

### Send commands to multiple readers

1. In Fleet select Linux and sh · xSpan / embedded.
2. Select readers individually or use Select all. Eligible online devices controlled by the current account are targeted.
3. Run the command and review pending, running, completed, failed or expired state and output per reader.

```sh
printf 'FLEET_CHECK_OK\n'
uname -m
uptime
```

> Batch submission does not guarantee synchronized execution. Queue polling and network conditions affect start time. Commands interrupted by an ambiguous disconnect are not silently replayed; inspect results before retrying.

### Open the RFID dashboard

Use Open xSpan dashboard in the device list or terminal to open the original OEM UI in a new tab. Sign in with the OEM administrator account. The dashboard can be used alongside the terminal.

> New readers require dashboard enablement after terminal enrollment. Give your integration contact the StreamZet device UUID and the HTTPS 9000 certificate SHA256 fingerprint verified through a trusted channel. The button appears after its pin and capability are provisioned. Update the pin when replacing the certificate.

Web connections expire after 30 minutes and can be ended immediately with Close dashboard. Long-inactive tabs may need reopening. A shared URL alone does not grant access from another browser.

### Execution limits

| Item | Limit |
| --- | --- |
| Terminal | One per reader, up to 30 minutes per session |
| Concurrent commands | Up to two per reader |
| Command length | 4,096 UTF-8 bytes |
| Command timeout | 100–120,000 ms; current Fleet UI uses 30,000 ms |
| Output | 65,536 bytes combined stdout/stderr; truncation is reported |
| Queue polling | Approximately every 30 seconds |

### Update and remove

1. Verify new artifact checksums and back up the current engine and startup configuration.
2. Stop only StreamZet and confirm it has exited. Stopping the engine closes its remote terminal, so use the OEM deployment path for replacement.
3. Replace only the engine and required CA/scripts. Preserve state/, registration.key, device name and ownership.
4. Restart and confirm the same device UUID returns online. Restore the backed-up executable if needed.

To remove the integration, stop StreamZet and remove only its startup hook. Keep identity state if reinstalling. When retiring a reader, have an administrator revoke that device’s server-side credentials and securely remove local secrets.

## Network and authentication

Network requirements, credential roles and operator privileges.

### Network requirements

| Connection | Requirement |
| --- | --- |
| Reader → relay | streamzet-embedded.plitsoft.workers.dev · TCP 443 · HTTPS/WSS |
| Operator browser | streamzet.com · streamzet-embedded.plitsoft.workers.dev · *.supabase.co · HTTPS/WSS |
| OEM web dashboard | streamzet-xspan-dashboard.plitsoft.workers.dev · HTTPS |
| Inside the reader | Dashboard traffic reaches loopback TLS 9000; no inbound port forwarding required. |

The reader initiates outbound TLS, allowing operation behind NAT. DNS, a correct clock and WebSocket-compatible egress are required. Retain CA and hostname verification.

### Credential roles

| Credential | Purpose |
| --- | --- |
| Enrollment key | Enrolls new readers; does not grant operator terminal or Fleet authority. |
| Device secret | Stored in state/identity; unique per reader and used for its connection. |
| Operator login | Authorizes terminal, commands and dashboard access after ownership checks. |
| OEM login | Separate Basic authentication for the original RFID dashboard. |

> Keep enrollment keys, passwords and device state out of public documentation, source repositories, SDK ZIPs and logs. Use 0700 provisioning directories and 0600 secret files; never clone them between readers.

### Privileges and authentication boundaries

Shells run with the installed agent’s OS privileges. The qualified reader’s OEM environment runs as root. The OEM must choose and qualify the deployment UID and file access scope.

The RFID UI uses a separate web origin from the StreamZet console. A one-use launch ticket and HttpOnly session cookie protect access; operator Bearer tokens are not forwarded to the reader. The reader’s HTTPS certificate is checked against a provisioned SHA256 fingerprint.

## Troubleshooting and acceptance

Diagnostic steps by symptom and partner acceptance checks.

### Diagnose by symptom

| Symptom | Check |
| --- | --- |
| Reader does not appear | Check time, DNS, outbound 443, enrollment key permission and account capacity. Identify readers by UUID, not name alone. |
| Private state directory is unavailable or already in use | Check state path, ownership and 0700 permissions. Check for simultaneous standalone and SDK processes. |
| Private enrollment configuration, entropy or identity failed | Check key/seed/identity file ownership, 0600 modes and contents. Do not substitute another reader’s state. |
| Invalid configuration, CA bundle or entropy source | Check the shipped CA bundle, seed and engine configuration. Keep certificate verification enabled. |
| Engine exits after successful start | Inspect poll exit status and stderr. start only confirms spawn. |
| Command is pending | Check online state, owner account and approximately 30-second queue interval. |
| Terminal already in use | End the existing session normally. Do not take over another operator’s session. |
| Dashboard button missing | Check online state and ask your contact to verify the certificate pin and dashboard enablement. |
| Dashboard 401/expired | Create a new connection using the StreamZet button. Use OEM credentials for an OEM authentication prompt. |
| Dashboard connection error | Check the OEM port 9000 service and certificate changes. Send updated fingerprints through a trusted channel. |

### Foreground diagnostics

start.sh discards output. If diagnostics are needed, first stop StreamZet and confirm exit. Then run the command below in an authorized reader shell to see stderr. Stop with Ctrl+C and restore the normal startup method.

```sh
cd /mnt/spp/streamzet-jci
./streamzet-embedded --production \
  streamzet-embedded.plitsoft.workers.dev \
  /mnt/spp/streamzet-jci/registration.key \
  /mnt/spp/streamzet-jci/cacert.pem \
  /mnt/spp/streamzet-jci/state 'xSpan R660 001'
```

### Partner acceptance checklist

- Does first startup enroll the reader and make it visible to the operator account?
- Have terminal output and successful/failed Fleet results been verified on the physical reader?
- Does the UUID survive app/engine restart, and does connectivity recover after a network outage?
- Do SDK start, poll, graceful stop and child reaping work inside the OEM application?
- During an approved maintenance window, has startup been verified after a full reboot and CAP/firmware update?
- Have CPU, memory, RFID workload and batch execution across multiple physical readers been tested?
- Have dashboard pin provisioning, login, live events and simultaneous terminal use been verified?

When requesting help, provide SDK version, reader model/firmware, UUID, timestamp with timezone, reproduction steps and redacted exit status/logs. Do not send keys, passwords or state/identity.

- [Contact technical support](mailto:support@streamzet.com)

## Packages and delivery

Choose the evaluation or product-integration package and verify the delivered files.

### Version 0.2.1 · delivery 2026-09-21

| Package | Contents |
| --- | --- |
| streamzet-xspan-evaluation-0.2.1-20260921.zip | ARMv5 engine, CA bundle, per-device provisioning tool, lifecycle scripts, docs and licenses. Test without compiling. |
| streamzet-jci-xspan-sdk-0.2.1-20260921.zip | Evaluation files plus the C/C++ process adapter, example, musl archives, source, pinned dependencies and build instructions. |
| *.zip.sha256 / SHA256SUMS | SHA256 checksums for archives and files inside them. Compare against the release metadata below. |

> Your integration contact supplies the binary and SDK packages directly. This public documentation contains no operator accounts, enrollment keys or device secrets. Verify delivered artifacts using the checksums below.

### Separately supplied credentials

- StreamZet operator account: device list, remote access and Fleet.
- Enrollment key file: used by prepare-device.py per reader. Do not hardcode it in SDK source.
- OEM dashboard credentials and a contact for enabling each new reader’s dashboard.

The xSpan adapter does not read the JCI-sdk-config.json used by other integrations. It uses the enrollment key file, CA bundle and persistent state path, and connects to the deployed relay.

### Offline documentation

- [Download Korean guide (.md)](https://streamzet.com/docs-assets/xspan/integration-ko.md)
- [Download English guide (.md)](https://streamzet.com/docs-assets/xspan/integration-en.md)

Both delivery ZIPs include these guides under docs/. The exact API contract is defined by streamzet_product.h in the SDK.

## Releases and verification

Engine versions and documentation/package revisions are tracked separately.

### 2026-09-21 · documentation/package revision

- Retains the qualified 0.2.1 engine. Separates evaluation and developer SDK ZIPs.
- Adds Korean/English integration docs, API contracts, installation, operations, troubleshooting and acceptance checks.
- Server/web support adds xSpan dashboard access and a steady terminal cursor. New readers require per-device dashboard provisioning.

Engine SHA256: d666b63e3040bef74828de0b6850e5f2fd4fd3c2fc06df84fc179f466ee512c0. Executable size: 500,920 bytes.

### 0.2.1 · 2026-09-17

Enables TCP_NODELAY on relay sockets. A concurrent relay-placement change reduced measured median terminal echo from 850 ms to 359 ms on the test path. This is a network-specific measurement, not an SLA. Device identity and protocol remain unchanged.

### 0.2.0 · initial production integration

Introduced account-based enrollment, per-device identity, authenticated remote terminal, sh Fleet commands and the POSIX product adapter.

### Completed and remaining qualification

| Validation | Scope |
| --- | --- |
| Physical R660 | Enrollment, terminal, Fleet success/failure/timeout/output limits, SDK lifecycle and same-UUID reconnect |
| Real browser | OEM navigation, reload, SSE events, concurrent terminal and unauthenticated access denial |
| Automation | ARM926 emulation, gateway race/access control, web type/build checks and pagination over 1,101 mock devices |
| Partner acceptance needed | OEM ETK build, other firmware, full reboot, production RFID workload and multiple physical readers |
